<!DOCTYPE html><html><head><meta charset="utf-8"><title>Angular - Angular Universal：服务端渲染</title><base href="/"><meta name="viewport" content="width=device-width,initial-scale=1"><link rel="search" type="application/opensearchdescription+xml" href="assets/opensearch.xml"><link rel="icon" type="image/x-icon" href="assets/images/favicons/favicon.ico"><link rel="icon" type="image/png" href="assets/images/favicons/favicon-32x32.png" sizes="32x32"><link rel="icon" type="image/png" href="assets/images/favicons/favicon-194x194.png" sizes="194x194"><link rel="icon" type="image/png" href="assets/images/favicons/favicon-96x96.png" sizes="96x96"><link rel="icon" type="image/png" href="assets/images/favicons/favicon-16x16.png" sizes="16x16"><link rel="apple-touch-icon" sizes="144x144" href="assets/images/favicons/favicon-144x144.png"><link rel="apple-touch-icon-precomposed" sizes="144x144" href="assets/images/favicons/favicon-144x144.png"><link href="assets/fonts/Material_Icons.css" rel="stylesheet"><link href="assets/fonts/Droid_Sans_Mono.css" rel="stylesheet"><link href="https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet"><link rel="manifest" href="pwa-manifest.json"><meta name="theme-color" content="#1976d2"><meta name="apple-mobile-web-app-capable" content="yes"><meta name="apple-mobile-web-app-status-bar-style" content="translucent"><script async="" src="assets/js/analytics.js"></script><script>!function(e,a,n,t,s,c,g){e.GoogleAnalyticsObject=s,e.ga=e.ga||function(){(e.ga.q=e.ga.q||[]).push(arguments)},e.ga.l=1*new Date,c=a.createElement(n),g=a.getElementsByTagName(n)[0],c.async=1,c.src="assets/js/analytics.js",~e.name.indexOf("NG_DEFER_BOOTSTRAP")||g.parentNode.insertBefore(c,g)}(window,document,"script",0,"ga")</script><script>window.onerror=function(){ga("send","exception",{exDescription:function(e,r,n,a,c){var l;e=e.replace(/^Error: /,""),l=c?c.stack.replace(/^Error: /,"").replace(e+"\n","").replace(/^ +/gm,"").replace(/^at /gm,"").replace(/(?: \(|@)http.+\/([^/)]+)\)?(?:\n|$)/gm,"@$1\n").replace(/ *\(eval code(:\d+:\d+)\)(?:\n|$)/gm,"@???$1\n"):r+":"+(n=n||"?")+":"+(a=a||"?");return(e+"\n"+l).substr(0,150)}.apply(null,arguments),exFatal:!0})}</script><script nomodule="" src="generated/ie-polyfills.min.js"></script><link rel="stylesheet" href="styles.10ba6936decaea45eabb.css"><style>@media screen and (-ms-high-contrast:active){.mat-toolbar{outline:solid 1px}}.mat-toolbar-row,.mat-toolbar-single-row{display:flex;box-sizing:border-box;padding:0 16px;width:100%;flex-direction:row;align-items:center;white-space:nowrap}.mat-toolbar-multiple-rows{display:flex;box-sizing:border-box;flex-direction:column;width:100%}.mat-toolbar-multiple-rows{min-height:64px}.mat-toolbar-row,.mat-toolbar-single-row{height:64px}@media (max-width:599px){.mat-toolbar-multiple-rows{min-height:56px}.mat-toolbar-row,.mat-toolbar-single-row{height:56px}}</style><style>.mat-icon{background-repeat:no-repeat;display:inline-block;fill:currentColor;height:24px;width:24px}.mat-icon.mat-icon-inline{font-size:inherit;height:inherit;line-height:inherit;width:inherit}[dir=rtl] .mat-icon-rtl-mirror{transform:scale(-1,1)}.mat-form-field:not(.mat-form-field-appearance-legacy) .mat-form-field-prefix .mat-icon,.mat-form-field:not(.mat-form-field-appearance-legacy) .mat-form-field-suffix .mat-icon{display:block}.mat-form-field:not(.mat-form-field-appearance-legacy) .mat-form-field-prefix .mat-icon-button .mat-icon,.mat-form-field:not(.mat-form-field-appearance-legacy) .mat-form-field-suffix .mat-icon-button .mat-icon{margin:auto}</style><style>.mat-button .mat-button-focus-overlay,.mat-icon-button .mat-button-focus-overlay{opacity:0}.mat-button:hover .mat-button-focus-overlay,.mat-stroked-button:hover .mat-button-focus-overlay{opacity:.04}@media (hover:none){.mat-button:hover .mat-button-focus-overlay,.mat-stroked-button:hover .mat-button-focus-overlay{opacity:0}}.mat-button,.mat-flat-button,.mat-icon-button,.mat-stroked-button{box-sizing:border-box;position:relative;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;cursor:pointer;outline:0;border:none;-webkit-tap-highlight-color:transparent;display:inline-block;white-space:nowrap;text-decoration:none;vertical-align:baseline;text-align:center;margin:0;min-width:64px;line-height:36px;padding:0 16px;border-radius:4px;overflow:visible}.mat-button::-moz-focus-inner,.mat-flat-button::-moz-focus-inner,.mat-icon-button::-moz-focus-inner,.mat-stroked-button::-moz-focus-inner{border:0}.mat-button[disabled],.mat-flat-button[disabled],.mat-icon-button[disabled],.mat-stroked-button[disabled]{cursor:default}.mat-button.cdk-keyboard-focused .mat-button-focus-overlay,.mat-button.cdk-program-focused .mat-button-focus-overlay,.mat-flat-button.cdk-keyboard-focused .mat-button-focus-overlay,.mat-flat-button.cdk-program-focused .mat-button-focus-overlay,.mat-icon-button.cdk-keyboard-focused .mat-button-focus-overlay,.mat-icon-button.cdk-program-focused .mat-button-focus-overlay,.mat-stroked-button.cdk-keyboard-focused .mat-button-focus-overlay,.mat-stroked-button.cdk-program-focused .mat-button-focus-overlay{opacity:.12}.mat-button::-moz-focus-inner,.mat-flat-button::-moz-focus-inner,.mat-icon-button::-moz-focus-inner,.mat-stroked-button::-moz-focus-inner{border:0}.mat-raised-button{box-sizing:border-box;position:relative;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;cursor:pointer;outline:0;border:none;-webkit-tap-highlight-color:transparent;display:inline-block;white-space:nowrap;text-decoration:none;vertical-align:baseline;text-align:center;margin:0;min-width:64px;line-height:36px;padding:0 16px;border-radius:4px;overflow:visible;transform:translate3d(0,0,0);transition:background .4s cubic-bezier(.25,.8,.25,1),box-shadow 280ms cubic-bezier(.4,0,.2,1)}.mat-raised-button::-moz-focus-inner{border:0}.mat-raised-button[disabled]{cursor:default}.mat-raised-button.cdk-keyboard-focused .mat-button-focus-overlay,.mat-raised-button.cdk-program-focused .mat-button-focus-overlay{opacity:.12}.mat-raised-button::-moz-focus-inner{border:0}._mat-animation-noopable.mat-raised-button{transition:none;animation:none}.mat-stroked-button{border:1px solid currentColor;padding:0 15px;line-height:34px}.mat-fab{box-sizing:border-box;position:relative;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;cursor:pointer;outline:0;border:none;-webkit-tap-highlight-color:transparent;display:inline-block;white-space:nowrap;text-decoration:none;vertical-align:baseline;text-align:center;margin:0;min-width:64px;line-height:36px;padding:0 16px;border-radius:4px;overflow:visible;transform:translate3d(0,0,0);transition:background .4s cubic-bezier(.25,.8,.25,1),box-shadow 280ms cubic-bezier(.4,0,.2,1);min-width:0;border-radius:50%;width:56px;height:56px;padding:0;flex-shrink:0}.mat-fab::-moz-focus-inner{border:0}.mat-fab[disabled]{cursor:default}.mat-fab.cdk-keyboard-focused .mat-button-focus-overlay,.mat-fab.cdk-program-focused .mat-button-focus-overlay{opacity:.12}.mat-fab::-moz-focus-inner{border:0}._mat-animation-noopable.mat-fab{transition:none;animation:none}.mat-fab .mat-button-wrapper{padding:16px 0;display:inline-block;line-height:24px}.mat-mini-fab{box-sizing:border-box;position:relative;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;cursor:pointer;outline:0;border:none;-webkit-tap-highlight-color:transparent;display:inline-block;white-space:nowrap;text-decoration:none;vertical-align:baseline;text-align:center;margin:0;min-width:64px;line-height:36px;padding:0 16px;border-radius:4px;overflow:visible;transform:translate3d(0,0,0);transition:background .4s cubic-bezier(.25,.8,.25,1),box-shadow 280ms cubic-bezier(.4,0,.2,1);min-width:0;border-radius:50%;width:40px;height:40px;padding:0;flex-shrink:0}.mat-mini-fab::-moz-focus-inner{border:0}.mat-mini-fab[disabled]{cursor:default}.mat-mini-fab.cdk-keyboard-focused .mat-button-focus-overlay,.mat-mini-fab.cdk-program-focused .mat-button-focus-overlay{opacity:.12}.mat-mini-fab::-moz-focus-inner{border:0}._mat-animation-noopable.mat-mini-fab{transition:none;animation:none}.mat-mini-fab .mat-button-wrapper{padding:8px 0;display:inline-block;line-height:24px}.mat-icon-button{padding:0;min-width:0;width:40px;height:40px;flex-shrink:0;line-height:40px;border-radius:50%}.mat-icon-button .mat-icon,.mat-icon-button i{line-height:24px}.mat-button-focus-overlay,.mat-button-ripple.mat-ripple{top:0;left:0;right:0;bottom:0;position:absolute;pointer-events:none;border-radius:inherit}.mat-button-focus-overlay{border-radius:inherit;opacity:0;transition:opacity .2s cubic-bezier(.35,0,.25,1),background-color .2s cubic-bezier(.35,0,.25,1)}._mat-animation-noopable .mat-button-focus-overlay{transition:none}@media screen and (-ms-high-contrast:active){.mat-button-focus-overlay{background-color:rgba(255,255,255,.5)}}.mat-button-ripple-round{border-radius:50%;z-index:1}.mat-button .mat-button-wrapper>*,.mat-fab .mat-button-wrapper>*,.mat-flat-button .mat-button-wrapper>*,.mat-icon-button .mat-button-wrapper>*,.mat-mini-fab .mat-button-wrapper>*,.mat-raised-button .mat-button-wrapper>*,.mat-stroked-button .mat-button-wrapper>*{vertical-align:middle}.mat-form-field:not(.mat-form-field-appearance-legacy) .mat-form-field-prefix .mat-icon-button,.mat-form-field:not(.mat-form-field-appearance-legacy) .mat-form-field-suffix .mat-icon-button{display:block;font-size:inherit;width:2.5em;height:2.5em}@media screen and (-ms-high-contrast:active){.mat-button,.mat-fab,.mat-flat-button,.mat-icon-button,.mat-mini-fab,.mat-raised-button{outline:solid 1px}}</style><style>.mat-drawer-container{position:relative;z-index:1;box-sizing:border-box;-webkit-overflow-scrolling:touch;display:block;overflow:hidden}.mat-drawer-container[fullscreen]{top:0;left:0;right:0;bottom:0;position:absolute}.mat-drawer-container[fullscreen].mat-drawer-opened{overflow:hidden}.mat-drawer-container.mat-drawer-container-explicit-backdrop .mat-drawer-side{z-index:3}.mat-drawer-container.ng-animate-disabled .mat-drawer-backdrop,.mat-drawer-container.ng-animate-disabled .mat-drawer-content,.ng-animate-disabled .mat-drawer-container .mat-drawer-backdrop,.ng-animate-disabled .mat-drawer-container .mat-drawer-content{transition:none}.mat-drawer-backdrop{top:0;left:0;right:0;bottom:0;position:absolute;display:block;z-index:3;visibility:hidden}.mat-drawer-backdrop.mat-drawer-shown{visibility:visible}.mat-drawer-transition .mat-drawer-backdrop{transition-duration:.4s;transition-timing-function:cubic-bezier(.25,.8,.25,1);transition-property:background-color,visibility}@media screen and (-ms-high-contrast:active){.mat-drawer-backdrop{opacity:.5}}.mat-drawer-content{position:relative;z-index:1;display:block;height:100%;overflow:auto}.mat-drawer-transition .mat-drawer-content{transition-duration:.4s;transition-timing-function:cubic-bezier(.25,.8,.25,1);transition-property:transform,margin-left,margin-right}.mat-drawer{position:relative;z-index:4;display:block;position:absolute;top:0;bottom:0;z-index:3;outline:0;box-sizing:border-box;overflow-y:auto;transform:translate3d(-100%,0,0)}@media screen and (-ms-high-contrast:active){.mat-drawer,[dir=rtl] .mat-drawer.mat-drawer-end{border-right:solid 1px currentColor}}@media screen and (-ms-high-contrast:active){.mat-drawer.mat-drawer-end,[dir=rtl] .mat-drawer{border-left:solid 1px currentColor;border-right:none}}.mat-drawer.mat-drawer-side{z-index:2}.mat-drawer.mat-drawer-end{right:0;transform:translate3d(100%,0,0)}[dir=rtl] .mat-drawer{transform:translate3d(100%,0,0)}[dir=rtl] .mat-drawer.mat-drawer-end{left:0;right:auto;transform:translate3d(-100%,0,0)}.mat-drawer-inner-container{width:100%;height:100%;overflow:auto;-webkit-overflow-scrolling:touch}.mat-sidenav-fixed{position:fixed}</style><style>.nav-link.highlight[_ngcontent-c5]{color:#ff0}</style><style>.mat-progress-bar{display:block;height:4px;overflow:hidden;position:relative;transition:opacity 250ms linear;width:100%}._mat-animation-noopable.mat-progress-bar{transition:none;animation:none}.mat-progress-bar .mat-progress-bar-element,.mat-progress-bar .mat-progress-bar-fill::after{height:100%;position:absolute;width:100%}.mat-progress-bar .mat-progress-bar-background{width:calc(100% + 10px)}@media screen and (-ms-high-contrast:active){.mat-progress-bar .mat-progress-bar-background{display:none}}.mat-progress-bar .mat-progress-bar-buffer{transform-origin:top left;transition:transform 250ms ease}@media screen and (-ms-high-contrast:active){.mat-progress-bar .mat-progress-bar-buffer{border-top:solid 5px;opacity:.5}}.mat-progress-bar .mat-progress-bar-secondary{display:none}.mat-progress-bar .mat-progress-bar-fill{animation:none;transform-origin:top left;transition:transform 250ms ease}@media screen and (-ms-high-contrast:active){.mat-progress-bar .mat-progress-bar-fill{border-top:solid 4px}}.mat-progress-bar .mat-progress-bar-fill::after{animation:none;content:'';display:inline-block;left:0}.mat-progress-bar[dir=rtl],[dir=rtl] .mat-progress-bar{transform:rotateY(180deg)}.mat-progress-bar[mode=query]{transform:rotateZ(180deg)}.mat-progress-bar[mode=query][dir=rtl],[dir=rtl] .mat-progress-bar[mode=query]{transform:rotateZ(180deg) rotateY(180deg)}.mat-progress-bar[mode=indeterminate] .mat-progress-bar-fill,.mat-progress-bar[mode=query] .mat-progress-bar-fill{transition:none}.mat-progress-bar[mode=indeterminate] .mat-progress-bar-primary,.mat-progress-bar[mode=query] .mat-progress-bar-primary{-webkit-backface-visibility:hidden;backface-visibility:hidden;animation:mat-progress-bar-primary-indeterminate-translate 2s infinite linear;left:-145.166611%}.mat-progress-bar[mode=indeterminate] .mat-progress-bar-primary.mat-progress-bar-fill::after,.mat-progress-bar[mode=query] .mat-progress-bar-primary.mat-progress-bar-fill::after{-webkit-backface-visibility:hidden;backface-visibility:hidden;animation:mat-progress-bar-primary-indeterminate-scale 2s infinite linear}.mat-progress-bar[mode=indeterminate] .mat-progress-bar-secondary,.mat-progress-bar[mode=query] .mat-progress-bar-secondary{-webkit-backface-visibility:hidden;backface-visibility:hidden;animation:mat-progress-bar-secondary-indeterminate-translate 2s infinite linear;left:-54.888891%;display:block}.mat-progress-bar[mode=indeterminate] .mat-progress-bar-secondary.mat-progress-bar-fill::after,.mat-progress-bar[mode=query] .mat-progress-bar-secondary.mat-progress-bar-fill::after{-webkit-backface-visibility:hidden;backface-visibility:hidden;animation:mat-progress-bar-secondary-indeterminate-scale 2s infinite linear}.mat-progress-bar[mode=buffer] .mat-progress-bar-background{-webkit-backface-visibility:hidden;backface-visibility:hidden;animation:mat-progress-bar-background-scroll 250ms infinite linear;display:block}.mat-progress-bar._mat-animation-noopable .mat-progress-bar-background,.mat-progress-bar._mat-animation-noopable .mat-progress-bar-buffer,.mat-progress-bar._mat-animation-noopable .mat-progress-bar-fill,.mat-progress-bar._mat-animation-noopable .mat-progress-bar-fill::after,.mat-progress-bar._mat-animation-noopable .mat-progress-bar-primary,.mat-progress-bar._mat-animation-noopable .mat-progress-bar-primary.mat-progress-bar-fill::after,.mat-progress-bar._mat-animation-noopable .mat-progress-bar-secondary,.mat-progress-bar._mat-animation-noopable .mat-progress-bar-secondary.mat-progress-bar-fill::after{animation:none;transition:none}@keyframes mat-progress-bar-primary-indeterminate-translate{0%{transform:translateX(0)}20%{animation-timing-function:cubic-bezier(.5,0,.70173,.49582);transform:translateX(0)}59.15%{animation-timing-function:cubic-bezier(.30244,.38135,.55,.95635);transform:translateX(83.67142%)}100%{transform:translateX(200.61106%)}}@keyframes mat-progress-bar-primary-indeterminate-scale{0%{transform:scaleX(.08)}36.65%{animation-timing-function:cubic-bezier(.33473,.12482,.78584,1);transform:scaleX(.08)}69.15%{animation-timing-function:cubic-bezier(.06,.11,.6,1);transform:scaleX(.66148)}100%{transform:scaleX(.08)}}@keyframes mat-progress-bar-secondary-indeterminate-translate{0%{animation-timing-function:cubic-bezier(.15,0,.51506,.40969);transform:translateX(0)}25%{animation-timing-function:cubic-bezier(.31033,.28406,.8,.73371);transform:translateX(37.65191%)}48.35%{animation-timing-function:cubic-bezier(.4,.62704,.6,.90203);transform:translateX(84.38617%)}100%{transform:translateX(160.27778%)}}@keyframes mat-progress-bar-secondary-indeterminate-scale{0%{animation-timing-function:cubic-bezier(.15,0,.51506,.40969);transform:scaleX(.08)}19.15%{animation-timing-function:cubic-bezier(.31033,.28406,.8,.73371);transform:scaleX(.4571)}44.15%{animation-timing-function:cubic-bezier(.4,.62704,.6,.90203);transform:scaleX(.72796)}100%{transform:scaleX(.08)}}@keyframes mat-progress-bar-background-scroll{to{transform:translateX(-8px)}}</style><script charset="utf-8" src="toc-toc-module-ngfactory.36694c537d7ff0b2c081.js"></script><script charset="utf-8" src="default~code-code-example-module-ngfactory~code-code-tabs-module-ngfactory~getting-started-ng-for-ng~82f414e5.c64b8abba8f3b7168616.js"></script><script charset="utf-8" src="default~code-code-example-module-ngfactory~code-code-tabs-module-ngfactory.98830c4eaea3268880de.js"></script><script charset="utf-8" src="code-code-example-module-ngfactory.bb14a03c7095ffd0e7bd.js"></script><script charset="utf-8" src="21.d3ebf64aa7b6d3a4b8f6.js"></script></head><body><aio-shell ng-version="7.0.0" class="mode-stable sidenav-open page-guide-universal folder-guide view-SideNav aio-notification-show"><div id="top-of-page"></div><mat-toolbar class="app-toolbar no-print mat-toolbar mat-primary mat-toolbar-multiple-rows" color="primary"><mat-toolbar-row class="notification-container mat-toolbar-row"><aio-notification expirationdate="2019-03-01" notificationid="survey-february-2019" class="ng-tns-c2-0 ng-trigger ng-trigger-hideAnimation"><span class="content"><a href="http://bit.ly/angular-survey-2019" target="_blank"><mat-icon aria-label="Announcement" class="icon mat-icon" role="img" svgicon="insert_comment" aria-hidden="true"><svg focusable="false" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M20 2H4c-1.1 0-2 .9-2 2v12c0 1.1.9 2 2 2h14l4 4V4c0-1.1-.9-2-2-2zm-2 12H6v-2h12v2zm0-3H6V9h12v2zm0-3H6V6h12v2z"></path><path d="M0 0h24v24H0z" fill="none"></path></svg></mat-icon><span class="message"><b>填写这份《一分钟调查》</b>，帮我们（开发组）做得更好！</span><span class="action-button">去填写</span></a></span><button class="close-button mat-icon-button" aria-label="Close" mat-icon-button=""><span class="mat-button-wrapper"><mat-icon aria-label="Dismiss notification" class="mat-icon ng-tns-c2-0" role="img" svgicon="close" aria-hidden="true"><svg focusable="false" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z"></path><path d="M0 0h24v24H0z" fill="none"></path></svg></mat-icon></span><div class="mat-button-ripple mat-ripple mat-button-ripple-round" matripple=""></div><div class="mat-button-focus-overlay"></div></button></aio-notification></mat-toolbar-row><mat-toolbar-row class="mat-toolbar-row"><button class="hamburger mat-button" mat-button="" title="Docs menu"><span class="mat-button-wrapper"><mat-icon class="mat-icon" role="img" svgicon="menu" aria-hidden="true"><svg focusable="false" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M3 18h18v-2H3v2zm0-5h18v-2H3v2zm0-7v2h18V6H3z"></path></svg></mat-icon></span><div class="mat-button-ripple mat-ripple" matripple=""></div><div class="mat-button-focus-overlay"></div></button><a class="nav-link home" href="/"><img alt="Home" height="40" src="assets/images/logos/angular/logo-nav@2x.png" title="Home" width="150" class="ng-star-inserted"></a><aio-top-menu _nghost-c5="" class="ng-star-inserted"><ul _ngcontent-c5="" role="navigation"><li _ngcontent-c5="" class="ng-star-inserted"><a _ngcontent-c5="" class="nav-link" href="features" title="特性"><span _ngcontent-c5="" class="nav-link-inner">特性</span></a></li><li _ngcontent-c5="" class="ng-star-inserted"><a _ngcontent-c5="" class="nav-link" href="docs" title="文档"><span _ngcontent-c5="" class="nav-link-inner">文档</span></a></li><li _ngcontent-c5="" class="ng-star-inserted"><a _ngcontent-c5="" class="nav-link" href="resources" title="资源"><span _ngcontent-c5="" class="nav-link-inner">资源</span></a></li><li _ngcontent-c5="" class="ng-star-inserted"><a _ngcontent-c5="" class="nav-link" href="events" title="会议"><span _ngcontent-c5="" class="nav-link-inner">会议</span></a></li><li _ngcontent-c5="" class="ng-star-inserted"><a _ngcontent-c5="" class="nav-link" href="https://blog.angular.io/" title="博客"><span _ngcontent-c5="" class="nav-link-inner">博客</span></a></li><li _ngcontent-c5="" class="ng-star-inserted"><a _ngcontent-c5="" class="nav-link" href="translations/cn/home" title="关于中文版"><span _ngcontent-c5="" class="nav-link-inner">关于中文版</span></a></li></ul></aio-top-menu><aio-search-box class="search-container"><input aria-label="search" placeholder="搜索" type="search"></aio-search-box><div class="toolbar-external-icons-container"><a aria-label="Angular on twitter" href="https://twitter.com/angular" title="Twitter"><mat-icon class="mat-icon" role="img" svgicon="logos:twitter" aria-hidden="true"><svg focusable="false" viewBox="0 0 50 59" xmlns="http://www.w3.org/2000/svg"><path d="M50,9.3c-1.8,0.8-3.8,1.4-5.9,1.6c2.1-1.3,3.7-3.3,4.5-5.7c-2,1.2-4.2,2-6.5,2.5c-1.9-2-4.5-3.2-7.5-3.2c-5.7,0-10.3,4.6-10.3,10.3c0,0.8,0.1,1.6,0.3,2.3C16.1,16.7,8.5,12.6,3.5,6.4c-0.9,1.5-1.4,3.3-1.4,5.2c0,3.6,1.8,6.7,4.6,8.5C5,20,3.4,19.6,2,18.8c0,0,0,0.1,0,0.1c0,5,3.5,9.1,8.2,10.1c-0.9,0.2-1.8,0.4-2.7,0.4c-0.7,0-1.3-0.1-1.9-0.2c1.3,4.1,5.1,7,9.6,7.1c-3.5,2.8-7.9,4.4-12.7,4.4c-0.8,0-1.6,0-2.4-0.1c4.5,2.9,9.9,4.6,15.7,4.6c18.9,0,29.2-15.6,29.2-29.2c0-0.4,0-0.9,0-1.3C46.9,13.2,48.6,11.4,50,9.3z"></path></svg></mat-icon></a><a aria-label="Angular on github" href="https://github.com/angular/angular" title="GitHub"><mat-icon class="mat-icon" role="img" svgicon="logos:github" aria-hidden="true"><svg focusable="false" viewBox="0 0 51.8 50.4" xmlns="http://www.w3.org/2000/svg"><path d="M25.9,0.2C11.8,0.2,0.3,11.7,0.3,25.8c0,11.3,7.3,20.9,17.5,24.3c1.3,0.2,1.7-0.6,1.7-1.2c0-0.6,0-2.6,0-4.8c-7.1,1.5-8.6-3-8.6-3c-1.2-3-2.8-3.7-2.8-3.7c-2.3-1.6,0.2-1.6,0.2-1.6c2.6,0.2,3.9,2.6,3.9,2.6c2.3,3.9,6,2.8,7.5,2.1c0.2-1.7,0.9-2.8,1.6-3.4c-5.7-0.6-11.7-2.8-11.7-12.7c0-2.8,1-5.1,2.6-6.9c-0.3-0.7-1.1-3.3,0.3-6.8c0,0,2.1-0.7,7,2.6c2-0.6,4.2-0.9,6.4-0.9c2.2,0,4.4,0.3,6.4,0.9c4.9-3.3,7-2.6,7-2.6c1.4,3.5,0.5,6.1,0.3,6.8c1.6,1.8,2.6,4.1,2.6,6.9c0,9.8-6,12-11.7,12.6c0.9,0.8,1.7,2.4,1.7,4.7c0,3.4,0,6.2,0,7c0,0.7,0.5,1.5,1.8,1.2c10.2-3.4,17.5-13,17.5-24.3C51.5,11.7,40.1,0.2,25.9,0.2z"></path></svg></mat-icon></a></div></mat-toolbar-row></mat-toolbar><mat-sidenav-container class="sidenav-container mat-drawer-container mat-sidenav-container mat-drawer-transition has-floating-toc" role="main"><div class="mat-drawer-backdrop ng-star-inserted"></div><div class="cdk-visually-hidden cdk-focus-trap-anchor"></div><mat-sidenav class="sidenav mat-drawer mat-sidenav ng-tns-c7-1 ng-trigger ng-trigger-transform mat-drawer-side ng-star-inserted" tabindex="-1" style="transform:none;visibility:visible"><div class="mat-drawer-inner-container"><aio-nav-menu><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-1 collapsed ng-star-inserted" style="position:relative" href="guide/quickstart" title="对 Angular 和 Angular CLI 基础知识的简短介绍" target="_self">快速上手</a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><button class="vertical-menu-item heading level-1 collapsed ng-star-inserted" type="button" title="此《英雄指南》教程会带你用 TypeScript 一步步创建一个 Angular 应用。" aria-pressed="false">教程<mat-icon class="rotating-icon mat-icon" role="img" svgicon="keyboard_arrow_right" aria-hidden="true"><svg focusable="false" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M8.59 16.34l4.58-4.59-4.58-4.59L10 5.75l6 6-6 6z"></path></svg></mat-icon></button><div class="heading-children level-1 collapsed"><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-2 collapsed ng-star-inserted" style="position:relative" href="tutorial" title="《英雄指南》教程简介" target="_self">简介</a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-2 collapsed ng-star-inserted" style="position:relative" href="tutorial/toh-pt0" title="创建应用的外壳" target="_self">应用的“外壳”</a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-2 collapsed ng-star-inserted" style="position:relative" href="tutorial/toh-pt1" title="第一部分：构建一个简单的英雄编辑器" target="_self">1. 英雄编辑器</a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-2 collapsed ng-star-inserted" style="position:relative" href="tutorial/toh-pt2" title="第二部分：构建一个主从结构的页面，用于展现英雄列表。" target="_self">2. 显示英雄列表</a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-2 collapsed ng-star-inserted" style="position:relative" href="tutorial/toh-pt3" title="第三部分：把主从结构的页面重构成多个组件。" target="_self">3. 主从组件</a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-2 collapsed ng-star-inserted" style="position:relative" href="tutorial/toh-pt4" title="第四部分：创建一个可复用的服务来管理英雄数据。" target="_self">4. 服务</a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-2 collapsed ng-star-inserted" style="position:relative" href="tutorial/toh-pt5" title="第五部分：添加 Angular 路由器，并且学习在视图之间导航。" target="_self">5. 路由</a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-2 collapsed ng-star-inserted" style="position:relative" href="tutorial/toh-pt6" title="第六部分：通过 HTTP 来获取并保存英雄数据。" target="_self">6. HTTP</a></div></aio-nav-item></div></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><button class="vertical-menu-item heading level-1 collapsed ng-star-inserted" type="button" title="学习 Angular 的核心知识" aria-pressed="false">核心知识<mat-icon class="rotating-icon mat-icon" role="img" svgicon="keyboard_arrow_right" aria-hidden="true"><svg focusable="false" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M8.59 16.34l4.58-4.59-4.58-4.59L10 5.75l6 6-6 6z"></path></svg></mat-icon></button><div class="heading-children level-1 collapsed"><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><button class="vertical-menu-item heading level-2 collapsed ng-star-inserted" type="button" title="Angular 应用的基本构造块。" aria-pressed="false">架构<mat-icon class="rotating-icon mat-icon" role="img" svgicon="keyboard_arrow_right" aria-hidden="true"><svg focusable="false" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M8.59 16.34l4.58-4.59-4.58-4.59L10 5.75l6 6-6 6z"></path></svg></mat-icon></button><div class="heading-children level-2 collapsed"><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-3 collapsed ng-star-inserted" style="position:relative" href="guide/architecture" title="Angular 应用的基本构造块" target="_self">架构概览</a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-3 collapsed ng-star-inserted" style="position:relative" href="guide/architecture-modules" title="关于模块。" target="_self">模块（NgModule）简介</a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-3 collapsed ng-star-inserted" style="position:relative" href="guide/architecture-components" title="关于组件、模板和视图。" target="_self">组件简介</a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-3 collapsed ng-star-inserted" style="position:relative" href="guide/architecture-services" title="关于服务与依赖注入。" target="_self">服务与 DI 简介</a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-3 collapsed ng-star-inserted" style="position:relative" href="guide/architecture-next-steps" title="学完基础知识之后……" target="_self">后续步骤</a></div></aio-nav-item></div></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><button class="vertical-menu-item heading level-2 collapsed ng-star-inserted" type="button" title="使用数据绑定构建动态视图" aria-pressed="false">组件与模板<mat-icon class="rotating-icon mat-icon" role="img" svgicon="keyboard_arrow_right" aria-hidden="true"><svg focusable="false" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M8.59 16.34l4.58-4.59-4.58-4.59L10 5.75l6 6-6 6z"></path></svg></mat-icon></button><div class="heading-children level-2 collapsed"><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-3 collapsed ng-star-inserted" style="position:relative" href="guide/displaying-data" title="属性绑定可以帮助应用把数据显示在界面上" target="_self">显示数据</a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-3 collapsed ng-star-inserted" style="position:relative" href="guide/template-syntax" title="学习如何写模板，以便借助数据绑定机制显示数据并响应事件。" target="_self">模板语法</a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-3 collapsed ng-star-inserted" style="position:relative" href="guide/user-input" title="用户输入会触发 DOM 事件。Angular 会通过事件绑定来监听那些事件，并把修改后的值传回应用的组件和模型中。" target="_self">用户输入</a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-3 collapsed ng-star-inserted" style="position:relative" href="guide/lifecycle-hooks" title="Angular 调用指令和组件的生命周期钩子函数，包括它的创建、变更和销毁时。" target="_self">生命周期钩子</a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-3 collapsed ng-star-inserted" style="position:relative" href="guide/component-interaction" title="在不同的指令和组件之间共享信息" target="_self">组件交互</a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-3 collapsed ng-star-inserted" style="position:relative" href="guide/component-styles" title="添加专属于某个组件的样式" target="_self">组件样式</a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-3 collapsed ng-star-inserted" style="position:relative" href="guide/elements" title="把组件转换成自定义元素。" target="_self">Angular 自定义元素</a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-3 collapsed ng-star-inserted" style="position:relative" href="guide/dynamic-component-loader" title="动态加载组件" target="_self">动态组件</a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-3 collapsed ng-star-inserted" style="position:relative" href="guide/attribute-directives" title="属性型指令把行为添加到现有元素上。" target="_self">属性型指令</a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-3 collapsed ng-star-inserted" style="position:relative" href="guide/structural-directives" title="结构型指令可以操纵页面的布局" target="_self">结构型指令</a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-3 collapsed ng-star-inserted" style="position:relative" href="guide/pipes" title="管道可以在模板中转换显示的内容。" target="_self">管道</a></div></aio-nav-item></div></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><button class="vertical-menu-item heading level-2 collapsed ng-star-inserted" type="button" title="Angular 的表单" aria-pressed="false">表单<mat-icon class="rotating-icon mat-icon" role="img" svgicon="keyboard_arrow_right" aria-hidden="true"><svg focusable="false" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M8.59 16.34l4.58-4.59-4.58-4.59L10 5.75l6 6-6 6z"></path></svg></mat-icon></button><div class="heading-children level-2 collapsed"><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-3 collapsed ng-star-inserted" style="position:relative" href="guide/forms-overview" title="表单可以创建集中、高效、引人注目的输入体验。Angular 表单可以协调一组数据绑定控件，跟踪变更，验证输入，并表达错误信息。" target="_self">简介</a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-3 collapsed ng-star-inserted" style="position:relative" href="guide/reactive-forms" title="使用 FormBuilder、表单组和表单数组创建响应式表单。" target="_self">响应式表单</a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-3 collapsed ng-star-inserted" style="position:relative" href="guide/forms" title="使用指令和 Angular 模板语法创建模板驱动表单。" target="_self">模板驱动表单</a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-3 collapsed ng-star-inserted" style="position:relative" href="guide/form-validation" title="验证用户的表单输入" target="_self">表单验证</a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-3 collapsed ng-star-inserted" style="position:relative" href="guide/dynamic-form" title="使用 FormGroup 渲染动态表单。" target="_self">动态表单</a></div></aio-nav-item></div></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><button class="vertical-menu-item heading level-2 collapsed ng-star-inserted" type="button" title="Observable 与 RxJS" aria-pressed="false">Observable 与 RxJS<mat-icon class="rotating-icon mat-icon" role="img" svgicon="keyboard_arrow_right" aria-hidden="true"><svg focusable="false" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M8.59 16.34l4.58-4.59-4.58-4.59L10 5.75l6 6-6 6z"></path></svg></mat-icon></button><div class="heading-children level-2 collapsed"><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-3 collapsed ng-star-inserted" style="position:relative" href="guide/observables" title="" target="_self">可观察对象(Observable)</a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-3 collapsed ng-star-inserted" style="position:relative" href="guide/rx-library" title="" target="_self">RxJS 库</a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-3 collapsed ng-star-inserted" style="position:relative" href="guide/observables-in-angular" title="" target="_self">Angular 中的可观察对象</a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-3 collapsed ng-star-inserted" style="position:relative" href="guide/practical-observable-usage" title="" target="_self">用法实战</a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-3 collapsed ng-star-inserted" style="position:relative" href="guide/comparing-observables" title="" target="_self">与其它技术的比较</a></div></aio-nav-item></div></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-2 collapsed ng-star-inserted" style="position:relative" href="guide/bootstrapping" title="在应用的根模块（AppModule）中告诉 Angular 如何构造并引导引用。" target="_self">引导启动</a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><button class="vertical-menu-item heading level-2 collapsed ng-star-inserted" type="button" title="Angular 中的模块" aria-pressed="false">NgModule<mat-icon class="rotating-icon mat-icon" role="img" svgicon="keyboard_arrow_right" aria-hidden="true"><svg focusable="false" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M8.59 16.34l4.58-4.59-4.58-4.59L10 5.75l6 6-6 6z"></path></svg></mat-icon></button><div class="heading-children level-2 collapsed"><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-3 collapsed ng-star-inserted" style="position:relative" href="guide/ngmodules" title="使用 NgModule 让你的应用更高效" target="_self">NgModule 简介</a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-3 collapsed ng-star-inserted" style="position:relative" href="guide/ngmodule-vs-jsmodule" title="JavaScript 模块和 NgModule 之间的差异" target="_self">JS 模块 vs NgModule</a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-3 collapsed ng-star-inserted" style="position:relative" href="guide/frequent-ngmodules" title="介绍最常用的 NgModule" target="_self">常用模块</a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-3 collapsed ng-star-inserted" style="position:relative" href="guide/module-types" title="介绍特性模块的几种类型" target="_self">特性模块的分类</a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-3 collapsed ng-star-inserted" style="position:relative" href="guide/entry-components" title="关于 Angular 中入口组件的一切" target="_self">入口组件</a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-3 collapsed ng-star-inserted" style="position:relative" href="guide/feature-modules" title="创建特性模块，以组织你的代码" target="_self">特性模块</a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-3 collapsed ng-star-inserted" style="position:relative" href="guide/providers" title="服务提供商与 NgModule" target="_self">服务提供商</a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-3 collapsed ng-star-inserted" style="position:relative" href="guide/singleton-services" title="创建单例服务" target="_self">单例服务</a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-3 collapsed ng-star-inserted" style="position:relative" href="guide/lazy-loading-ngmodules" title="惰性加载模块，以提高应用的性能" target="_self">惰性加载的特性模块</a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-3 collapsed ng-star-inserted" style="position:relative" href="guide/sharing-ngmodules" title="共享 NgModule 让你的应用现代化。" target="_self">共享 NgModule</a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-3 collapsed ng-star-inserted" style="position:relative" href="guide/ngmodule-api" title="理解 NgModule 的那些细节。" target="_self">NgModule API</a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-3 collapsed ng-star-inserted" style="position:relative" href="guide/ngmodule-faq" title="回答关于 NgModules 的常见问题。" target="_self">NgModule 常见问题</a></div></aio-nav-item></div></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><button class="vertical-menu-item heading level-2 collapsed ng-star-inserted" type="button" title="依赖注入：创建并注入各种服务。" aria-pressed="false">依赖注入<mat-icon class="rotating-icon mat-icon" role="img" svgicon="keyboard_arrow_right" aria-hidden="true"><svg focusable="false" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M8.59 16.34l4.58-4.59-4.58-4.59L10 5.75l6 6-6 6z"></path></svg></mat-icon></button><div class="heading-children level-2 collapsed"><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-3 collapsed ng-star-inserted" style="position:relative" href="guide/dependency-injection" title="Angular 的依赖注入系统能够为 Angular 创建的类创建并交付它们所依赖的服务。" target="_self">Angular 依赖注入</a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-3 collapsed ng-star-inserted" style="position:relative" href="guide/hierarchical-dependency-injection" title="与组件树平行的注入器树，并支持嵌套的依赖。" target="_self">多级注入器</a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-3 collapsed ng-star-inserted" style="position:relative" href="guide/dependency-injection-providers" title="各种提供商类型的更多知识。" target="_self">DI 提供商</a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-3 collapsed ng-star-inserted" style="position:relative" href="guide/dependency-injection-in-action" title="依赖注入的使用技巧" target="_self">DI 实战</a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-3 collapsed ng-star-inserted" style="position:relative" href="guide/dependency-injection-navtree" title="使用注入器树来查找父组件。" target="_self">浏览组件树</a></div></aio-nav-item></div></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-2 collapsed ng-star-inserted" style="position:relative" href="guide/http" title="通过 HTTP 协议与远程服务器对话。" target="_self">HttpClient</a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-2 collapsed ng-star-inserted" style="position:relative" href="guide/router" title="揭示如何通过 Angular 路由进行基本的屏幕导航。" target="_self">路由与导航</a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><button class="vertical-menu-item heading level-2 collapsed ng-star-inserted" type="button" title="Angular 动画系统指南" aria-pressed="false">动画<mat-icon class="rotating-icon mat-icon" role="img" svgicon="keyboard_arrow_right" aria-hidden="true"><svg focusable="false" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M8.59 16.34l4.58-4.59-4.58-4.59L10 5.75l6 6-6 6z"></path></svg></mat-icon></button><div class="heading-children level-2 collapsed"><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-3 collapsed ng-star-inserted" style="position:relative" href="guide/animations" title="Angular 动画的基础技术。" target="_self">简介</a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-3 collapsed ng-star-inserted" style="position:relative" href="guide/transition-and-triggers" title="转场与触发器的高级技术。" target="_self">转场与触发器</a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-3 collapsed ng-star-inserted" style="position:relative" href="guide/complex-animation-sequences" title="复杂的 Angular 动画序列。" target="_self">复杂序列</a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-3 collapsed ng-star-inserted" style="position:relative" href="guide/reusable-animations" title="创建可复用的动画。" target="_self">可复用动画</a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-3 collapsed ng-star-inserted" style="position:relative" href="guide/route-animations" title="为路由提供转场动画。" target="_self">路由转场动画</a></div></aio-nav-item></div></div></aio-nav-item></div></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><button class="vertical-menu-item heading level-1 expanded selected ng-star-inserted" type="button" title="把 Angular 用到你的实际工作中的一些技巧" aria-pressed="true">其它技术<mat-icon class="rotating-icon mat-icon" role="img" svgicon="keyboard_arrow_right" aria-hidden="true"><svg focusable="false" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M8.59 16.34l4.58-4.59-4.58-4.59L10 5.75l6 6-6 6z"></path></svg></mat-icon></button><div class="heading-children level-1 expanded selected"><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-2 collapsed ng-star-inserted" style="position:relative" href="guide/security" title="Angular 应用开发中的安全技术。" target="_self">安全</a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-2 collapsed ng-star-inserted" style="position:relative" href="guide/i18n" title="把应用模板中的文本翻译成多种语言。" target="_self">国际化 (i18n)</a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><button class="vertical-menu-item heading level-2 collapsed ng-star-inserted" type="button" title="Angular Service Worker: 控制应用资源的缓存。" aria-pressed="false">Service Worker 与 PWA<mat-icon class="rotating-icon mat-icon" role="img" svgicon="keyboard_arrow_right" aria-hidden="true"><svg focusable="false" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M8.59 16.34l4.58-4.59-4.58-4.59L10 5.75l6 6-6 6z"></path></svg></mat-icon></button><div class="heading-children level-2 collapsed"><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-3 collapsed ng-star-inserted" style="position:relative" href="guide/service-worker-intro" title="Angular 对 Service Worker 的实现提升了慢速或不稳定的网络连接下的用户体验。" target="_self">简介</a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-3 collapsed ng-star-inserted" style="position:relative" href="guide/service-worker-getting-started" title="在 CLI 项目中启用 Service Worker，并在浏览器中查看效果。" target="_self">快速起步</a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-3 collapsed ng-star-inserted" style="position:relative" href="guide/service-worker-communications" title="那些能让你和 Angular 的 Service Worker 通讯的服务类。" target="_self">与 Service Worker 通讯</a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-3 collapsed ng-star-inserted" style="position:relative" href="guide/service-worker-devops" title="使用 Service Worker 运行应用、管理应用更新、调试以及杀掉正在运行的应用。" target="_self">生产环境下的 Service Worker</a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-3 collapsed ng-star-inserted" style="position:relative" href="guide/service-worker-config" title="配置 Service Worker 的缓存行为。" target="_self">Service Worker 配置</a></div></aio-nav-item></div></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-2 expanded selected ng-star-inserted" style="position:relative" href="guide/universal" title="使用 Angular Universal 在服务端渲染 HTML。" target="_self">服务端渲染</a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><button class="vertical-menu-item heading level-2 collapsed ng-star-inserted" type="button" title="把 AngularJS 应用增量式的升级到 Angular。" aria-pressed="false">从 AngularJS 升级<mat-icon class="rotating-icon mat-icon" role="img" svgicon="keyboard_arrow_right" aria-hidden="true"><svg focusable="false" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M8.59 16.34l4.58-4.59-4.58-4.59L10 5.75l6 6-6 6z"></path></svg></mat-icon></button><div class="heading-children level-2 collapsed"><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-3 collapsed ng-star-inserted" style="position:relative" href="guide/upgrade" title="把 AngularJS 应用增量式的升级到 Angular。" target="_self">升级步骤</a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-3 collapsed ng-star-inserted" style="position:relative" href="guide/upgrade-performance" title="用更灵活的方式把 AngularJS 升级到 Angular" target="_self">更关注性能的升级方式</a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-3 collapsed ng-star-inserted" style="position:relative" href="guide/ajs-quick-reference" title="学习如何把 AngularJS 的概念映射到 Angular 中。" target="_self">AngularJS 与 Angular 的概念对照</a></div></aio-nav-item></div></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><button class="vertical-menu-item heading level-2 collapsed ng-star-inserted" type="button" title="使用共享库扩展 Angular" aria-pressed="false">Angular 库开发<mat-icon class="rotating-icon mat-icon" role="img" svgicon="keyboard_arrow_right" aria-hidden="true"><svg focusable="false" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M8.59 16.34l4.58-4.59-4.58-4.59L10 5.75l6 6-6 6z"></path></svg></mat-icon></button><div class="heading-children level-2 collapsed"><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-3 collapsed ng-star-inserted" style="position:relative" href="guide/libraries" title="理解何时以及如何使用和创建库。" target="_self">库概览</a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-3 collapsed ng-star-inserted" style="position:relative" href="guide/using-libraries" title="把已发布的库集成进你的应用中。" target="_self">使用已发布的库</a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-3 collapsed ng-star-inserted" style="position:relative" href="guide/creating-libraries" title="通过创建、发布和使用你自己的库来扩展 Angular" target="_self">创建库</a></div></aio-nav-item></div></div></aio-nav-item></div></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><button class="vertical-menu-item heading level-1 collapsed ng-star-inserted" type="button" title="关于环境搭建、构建、测试、部署环境与工具的信息。" aria-pressed="false">环境搭建与部署<mat-icon class="rotating-icon mat-icon" role="img" svgicon="keyboard_arrow_right" aria-hidden="true"><svg focusable="false" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M8.59 16.34l4.58-4.59-4.58-4.59L10 5.75l6 6-6 6z"></path></svg></mat-icon></button><div class="heading-children level-1 collapsed"><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-2 collapsed ng-star-inserted" style="position:relative" href="guide/file-structure" title="Angular 工作区在文件系统中是怎样的。" target="_self">项目文件结构</a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-2 collapsed ng-star-inserted" style="position:relative" href="guide/workspace-config" title="&quot;angular.json&quot; 包含供 CLI 命令使用的工作区和项目默认配置。" target="_self">工作区配置</a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-2 collapsed ng-star-inserted" style="position:relative" href="guide/npm-packages" title="开发期间和运行期间所需的 npm 包的说明。" target="_self">npm 包</a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-2 collapsed ng-star-inserted" style="position:relative" href="guide/typescript-configuration" title="给 Angular 开发者的 TypeScript 配置。" target="_self">TypeScript 配置</a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-2 collapsed ng-star-inserted" style="position:relative" href="guide/aot-compiler" title="了解为何以及如何使用预先（AOT）编译器。" target="_self">预先（AOT）编译</a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-2 collapsed ng-star-inserted" style="position:relative" href="guide/build" title="构建应用及为应用启动开发服务器。" target="_self">构建与运行</a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-2 collapsed ng-star-inserted" style="position:relative" href="guide/testing" title="测试 Angular 应用的技巧与实践。" target="_self">测试</a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-2 collapsed ng-star-inserted" style="position:relative" href="guide/deployment" title="了解如何部署 Angular 应用。" target="_self">发布</a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-2 collapsed ng-star-inserted" style="position:relative" href="guide/browser-support" title="浏览器支持与腻子脚本指南。" target="_self">浏览器支持</a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><button class="vertical-menu-item heading level-2 collapsed ng-star-inserted" type="button" title="整合开发环境和工具。" aria-pressed="false">开发工具集成<mat-icon class="rotating-icon mat-icon" role="img" svgicon="keyboard_arrow_right" aria-hidden="true"><svg focusable="false" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M8.59 16.34l4.58-4.59-4.58-4.59L10 5.75l6 6-6 6z"></path></svg></mat-icon></button><div class="heading-children level-2 collapsed"><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-3 collapsed ng-star-inserted" style="position:relative" href="guide/language-service" title="使用 Angular 语言服务加速开发。" target="_self">语言服务</a></div></aio-nav-item></div></div></aio-nav-item></div></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><button class="vertical-menu-item heading level-1 collapsed ng-star-inserted" type="button" title="Angular 的版本发布实践、更新与升级。" aria-pressed="false">发布信息<mat-icon class="rotating-icon mat-icon" role="img" svgicon="keyboard_arrow_right" aria-hidden="true"><svg focusable="false" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M8.59 16.34l4.58-4.59-4.58-4.59L10 5.75l6 6-6 6z"></path></svg></mat-icon></button><div class="heading-children level-1 collapsed"><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-2 collapsed ng-star-inserted" style="position:relative" href="guide/updating" title="如何把 Angular 应用和库升级到最新版本。" target="_self">保持最新</a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-2 collapsed ng-star-inserted" style="position:relative" href="guide/releases" title="Angular 的版本、发布、支持、弃用策略与实践。" target="_self">Angular 发布策略与实践</a></div></aio-nav-item></div></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><button class="vertical-menu-item heading level-1 collapsed ng-star-inserted" type="button" title="Angular 语法、编码、术语汇总。" aria-pressed="false">快捷手册<mat-icon class="rotating-icon mat-icon" role="img" svgicon="keyboard_arrow_right" aria-hidden="true"><svg focusable="false" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M8.59 16.34l4.58-4.59-4.58-4.59L10 5.75l6 6-6 6z"></path></svg></mat-icon></button><div class="heading-children level-1 collapsed"><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-2 collapsed ng-star-inserted" style="position:relative" href="guide/cheatsheet" title="关于 Angular 常用编码技术的快速指南。" target="_self">速查表</a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-2 collapsed ng-star-inserted" style="position:relative" href="guide/styleguide" title="写出 Angular 风格的程序" target="_self">风格指南</a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-2 collapsed ng-star-inserted" style="position:relative" href="guide/glossary" title="Angular 中最重要的词汇的简要定义。" target="_self">词汇表</a></div></aio-nav-item></div></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><button class="vertical-menu-item heading level-1 collapsed ng-star-inserted" type="button" title="Angular CLI 命令参考手册。" aria-pressed="false">CLI 命令<mat-icon class="rotating-icon mat-icon" role="img" svgicon="keyboard_arrow_right" aria-hidden="true"><svg focusable="false" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M8.59 16.34l4.58-4.59-4.58-4.59L10 5.75l6 6-6 6z"></path></svg></mat-icon></button><div class="heading-children level-1 collapsed"><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-2 collapsed ng-star-inserted" style="position:relative" href="cli" title="CLI 工具介绍、命令、语法" target="_self">概览</a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-2 collapsed ng-star-inserted" style="position:relative" href="cli/add" title="ng add." target="_self">ng add</a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-2 collapsed ng-star-inserted" style="position:relative" href="cli/build" title="ng build." target="_self">ng build</a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-2 collapsed ng-star-inserted" style="position:relative" href="cli/config" title="ng config." target="_self">ng config</a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-2 collapsed ng-star-inserted" style="position:relative" href="cli/doc" title="ng doc." target="_self">ng doc</a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-2 collapsed ng-star-inserted" style="position:relative" href="cli/e2e" title="ng e2e." target="_self">ng e2e</a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-2 collapsed ng-star-inserted" style="position:relative" href="cli/generate" title="ng generate." target="_self">ng generate</a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-2 collapsed ng-star-inserted" style="position:relative" href="cli/help" title="ng help." target="_self">ng help</a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-2 collapsed ng-star-inserted" style="position:relative" href="cli/lint" title="ng lint." target="_self">ng lint</a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-2 collapsed ng-star-inserted" style="position:relative" href="cli/new" title="ng new." target="_self">ng new</a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-2 collapsed ng-star-inserted" style="position:relative" href="cli/run" title="ng run." target="_self">ng run</a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-2 collapsed ng-star-inserted" style="position:relative" href="cli/serve" title="ng serve." target="_self">ng serve</a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-2 collapsed ng-star-inserted" style="position:relative" href="cli/test" title="ng test." target="_self">ng test</a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-2 collapsed ng-star-inserted" style="position:relative" href="cli/update" title="ng update." target="_self">ng update</a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-2 collapsed ng-star-inserted" style="position:relative" href="cli/version" title="ng version." target="_self">ng version</a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-2 collapsed ng-star-inserted" style="position:relative" href="cli/xi18n" title="ng xi18n." target="_self">ng xi18n</a></div></aio-nav-item></div></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-1 collapsed ng-star-inserted" style="position:relative" href="api" title="关于 Angular 中类和值的详细信息。" target="_self">API 参考手册</a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><div class="mat-divider ng-star-inserted" style="margin:4px 20px;border-top:1px solid #d3d3d3"></div></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-1 collapsed ng-star-inserted" style="position:relative" href="https://ng-china.org" title="2018 ngChina 开发者大会" target="_blank">2018 ngChina @ 杭州<mat-icon class="mat-icon material-icons ng-star-inserted" role="img" aria-hidden="true">open_in_new</mat-icon></a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-1 collapsed ng-star-inserted" style="position:relative" href="https://github.com/ng-docs/ng-docs.github.io/issues" title="github 上的中文互助问答区" target="_blank">互助问答<mat-icon class="mat-icon material-icons ng-star-inserted" role="img" aria-hidden="true">open_in_new</mat-icon></a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-1 collapsed ng-star-inserted" style="position:relative" href="https://material.angular.cn" title="Angular Material 组件库的中文文档" target="_blank">官方 Material 组件库<mat-icon class="mat-icon material-icons ng-star-inserted" role="img" aria-hidden="true">open_in_new</mat-icon></a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-1 collapsed ng-star-inserted" style="position:relative" href="https://ng.ant.design/" title="Ant Design 的 Angular 实现，服务于企业级后台产品。" target="_blank">ng-zorro 组件库<mat-icon class="mat-icon material-icons ng-star-inserted" role="img" aria-hidden="true">open_in_new</mat-icon></a></div></aio-nav-item><aio-nav-item class="ng-star-inserted"><div class="ng-star-inserted"><a class="vertical-menu-item level-1 collapsed ng-star-inserted" style="position:relative" href="https://ng.mobile.ant.design/" title="Ant Design Mobile 的 Angular 实现，服务于无线产品。" target="_blank">ng-zorro mobile 组件库<mat-icon class="mat-icon material-icons ng-star-inserted" role="img" aria-hidden="true">open_in_new</mat-icon></a></div></aio-nav-item></aio-nav-menu><div class="doc-version"><aio-select><div class="form-select-menu"><button class="form-select-button"><strong></strong>stable (v8.0.0-beta.4)</button></div></aio-select></div></div></mat-sidenav><div class="cdk-visually-hidden cdk-focus-trap-anchor"></div><mat-sidenav-content cdkscrollable="" class="mat-drawer-content mat-sidenav-content ng-star-inserted" style="margin-left:260px"><main class="sidenav-content" role="main" id="guide-universal"><aio-mode-banner></aio-mode-banner><aio-doc-viewer class=""><div style="opacity:1"><div class="github-links"><a href="https://github.com/angular/angular-cn/edit/aio/aio/content/guide/universal.md?message=docs%3A%20请简述你的修改..." aria-label="提供编辑建议" title="提供编辑建议"><i class="material-icons" aria-hidden="true" role="img">mode_edit</i></a></div><div class="content"><h1 id="angular-universal-server-side-rendering" translation-result="on">Angular Universal：服务端渲染<a title="Link to this heading" class="header-link" aria-hidden="true" href="guide/universal#angular-universal-server-side-rendering"><i class="material-icons">link</i></a></h1><aio-toc class="embedded" ng-version="7.0.0"><div class="toc-inner no-print collapsed ng-star-inserted"><button aria-label="Expand/collapse contents" class="toc-heading embedded secondary ng-star-inserted" title="Expand/collapse contents" type="button" aria-pressed="false">目录<mat-icon class="rotating-icon mat-icon collapsed" role="img" svgicon="keyboard_arrow_right" aria-hidden="true"><svg focusable="false" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M8.59 16.34l4.58-4.59-4.58-4.59L10 5.75l6 6-6 6z"></path></svg></mat-icon></button><ul class="toc-list embedded"><li title="为何需要服务端渲染？link" class="h2 ng-star-inserted"><a href="guide/universal#why-use-server-side-rendering">为何需要服务端渲染？</a></li><li title="帮助网络爬虫link" class="h3 ng-star-inserted"><a href="guide/universal#facilitate-web-crawlers">帮助网络爬虫</a></li><li title="提升手机和低功耗设备上的性能link" class="h3 ng-star-inserted"><a href="guide/universal#improve-performance-on-mobile-and-low-powered-devices">提升手机和低功耗设备上的性能</a></li><li title="快速显示第一页link" class="h3 secondary ng-star-inserted"><a href="guide/universal#show-the-first-page-quickly">快速显示第一页</a></li><li title="Universal Web 服务器link" class="h2 secondary ng-star-inserted"><a href="guide/universal#universal-web-servers">Universal Web 服务器</a></li><li title="准备服务端渲染link" class="h2 secondary ng-star-inserted"><a href="guide/universal#preparing-for-server-side-rendering">准备服务端渲染</a></li><li title="步骤一：安装依赖link" class="h2 secondary ng-star-inserted"><a href="guide/universal#step-1-install-dependencies">步骤一：安装依赖</a></li><li title="步骤二：准备你的应用link" class="h2 secondary ng-star-inserted"><a href="guide/universal#step-2-prepare-your-app">步骤二：准备你的应用</a></li><li title="2a. 为应用添加 Universal 支持link" class="h3 secondary ng-star-inserted"><a href="guide/universal#2a-add-universal-support-to-your-app">2a. 为应用添加 Universal 支持</a></li><li title="2b. 创建服务端根模块link" class="h3 secondary ng-star-inserted"><a href="guide/universal#2b-create-a-server-root-module">2b. 创建服务端根模块</a></li><li title="2c. 创建一个 main 文件，导出 AppServerModulelink" class="h3 secondary ng-star-inserted"><a href="guide/universal#2c-create-a-main-file-to-export-appservermodule">2c. 创建一个 main 文件，导出 AppServerModule</a></li><li title="2d. 为 AppServerModule 创建配置文件link" class="h3 secondary ng-star-inserted"><a href="guide/universal#2d-create-a-configuration-file-for-appservermodule">2d. 为 AppServerModule 创建配置文件</a></li><li title="步骤三：创建新的构建目标，并打包link" class="h2 secondary ng-star-inserted"><a href="guide/universal#step-3-create-a-new-build-target-and-build-the-bundle">步骤三：创建新的构建目标，并打包</a></li><li title="步骤四：设置服务器环境，以运行 Universal 包link" class="h2 secondary ng-star-inserted"><a href="guide/universal#step-4-set-up-a-server-to-run-universal-bundles">步骤四：设置服务器环境，以运行 Universal 包</a></li><li title="步骤五：打包并在服务器上运行此应用link" class="h2 secondary ng-star-inserted"><a href="guide/universal#step-5-pack-and-run-the-app-on-the-server">步骤五：打包并在服务器上运行此应用</a></li><li title="创建一些脚本link" class="h3 secondary ng-star-inserted"><a href="guide/universal#creating-scripts">创建一些脚本</a></li><li title="使用浏览器 APIlink" class="h3 secondary ng-star-inserted"><a href="guide/universal#working-around-the-browser-apis">使用浏览器 API</a></li><li title="例子link" class="h2 secondary ng-star-inserted"><a href="guide/universal#universal-tutorial">例子</a></li><li title="在 HTTP 中使用绝对地址link" class="h3 secondary ng-star-inserted"><a href="guide/universal#using-absolute-urls-for-server-requests">在 HTTP 中使用绝对地址</a></li><li title="Universal 模板引擎link" class="h3 secondary ng-star-inserted"><a href="guide/universal#universal-template-engine">Universal 模板引擎</a></li><li title="过滤请求的 URLlink" class="h3 secondary ng-star-inserted"><a href="guide/universal#filtering-request-urls">过滤请求的 URL</a></li><li title="安全的提供静态文件link" class="h3 secondary ng-star-inserted"><a href="guide/universal#serving-static-files-safely">安全的提供静态文件</a></li><li title="Universal 实战link" class="h3 secondary ng-star-inserted"><a href="guide/universal#universal-in-action">Universal 实战</a></li></ul><button aria-label="Expand/collapse contents" class="toc-more-items embedded material-icons collapsed ng-star-inserted" title="Expand/collapse contents" type="button" aria-pressed="false"></button></div></aio-toc><h1 translation-origin="off" id="angular-universal-server-side-rendering">Angular Universal: server-side rendering<a title="Link to this heading" class="header-link" aria-hidden="true" href="guide/universal#angular-universal-server-side-rendering"><i class="material-icons">link</i></a></h1><p translation-result="on">本指南讲的是<strong>Angular Universal（统一平台）</strong>，一项在服务端运行 Angular 应用的技术。</p><p translation-origin="off">This guide describes <strong>Angular Universal</strong>, a technology that runs your Angular application on the server.</p><p translation-result="on">标准的 Angular 应用会运行在<em>浏览器</em>中，它会在 DOM 中渲染页面，以响应用户的操作。</p><p translation-origin="off">A normal Angular application executes in the <em>browser</em>, rendering pages in the DOM in response to user actions.</p><p translation-result="on">而<strong>Angular Universal</strong> 会在<em>服务端</em>通过一个名叫<strong>服务端渲染（server-side rendering - SSR）的过程</strong>生成<em>静态</em>的应用页面。</p><p translation-origin="off">Angular Universal generates <em>static</em> application pages on the <em>server</em> through a process called <em>server-side rendering</em> (SSR).</p><p translation-result="on">它可以生成这些页面，并在浏览器请求时直接用它们给出响应。 也可以把页面预先生成为 HTML 文件，然后把它们作为静态文件供服务器使用。</p><p translation-origin="off">When Universal is integrated with your app, it can generate and serve those pages in response to requests from browsers. It can also pre-generate pages as HTML files that you serve later.</p><p translation-result="on">你可以使用 <a href="guide/glossary#cli">Angular CLI</a> 来轻松为应用做好服务端渲染的准备。CLI 的 <code>@nguniversal/express-engine</code> 模板会执行下面所讲的必要步骤。</p><p translation-origin="off">You can easily prepare an app for server-side rendering using the <a href="guide/glossary#cli">Angular CLI</a>. The CLI schematic <code>@nguniversal/express-engine</code> performs the required steps, as described below.</p><p translation-result="on">本指南讲的是一个 Universal 的范例应用，它启动得和在服务端渲染好的页面一样快。 稍后，浏览器就会下载完整的客户端版本，并在代码加载完之后自动切换过去。</p><p translation-origin="off">This guide describes a Universal sample application that launches quickly as a server-rendered page. Meanwhile, the browser downloads the full client version and switches to it automatically after the code loads.</p><div class="alert is-helpful"><p translation-result="on">你可以<a href="generated/zips/universal/universal.zip">下载最终的范例代码</a>，并将其运行在一个 <a href="https://expressjs.com/">Node.js® Express</a> 服务器中。</p><p translation-origin="off"><strong>Note:</strong> <a href="generated/zips/universal/universal.zip">Download the finished sample code</a>, which runs in a <a href="https://expressjs.com/">Node.js® Express</a> server.</p></div><a id="why-do-it"></a><h2 id="why-use-server-side-rendering" translation-result="on">为何需要服务端渲染？<a title="Link to this heading" class="header-link" aria-hidden="true" href="guide/universal#why-use-server-side-rendering"><i class="material-icons">link</i></a></h2><h2 translation-origin="off" id="why-use-server-side-rendering">Why use server-side rendering?<a title="Link to this heading" class="header-link" aria-hidden="true" href="guide/universal#why-use-server-side-rendering"><i class="material-icons">link</i></a></h2><p translation-result="on">有三个主要的理由来为你的应用创建一个 Universal 版本。</p><p translation-origin="off">There are three main reasons to create a Universal version of your app.</p><ol><li><p translation-result="on">帮助网络爬虫（SEO）</p><p translation-origin="off">Facilitate web crawlers (SEO)</p></li><li><p translation-result="on">提升在手机和低功耗设备上的性能</p><p translation-origin="off">Improve performance on mobile and low-powered devices</p></li><li><p translation-result="on">迅速显示出第一个页面</p><p translation-origin="off">Show the first page quickly</p></li></ol><a id="seo"></a> <a id="web-crawlers"></a><h3 id="facilitate-web-crawlers" translation-result="on">帮助网络爬虫<a title="Link to this heading" class="header-link" aria-hidden="true" href="guide/universal#facilitate-web-crawlers"><i class="material-icons">link</i></a></h3><h3 translation-origin="off" id="facilitate-web-crawlers">Facilitate web crawlers<a title="Link to this heading" class="header-link" aria-hidden="true" href="guide/universal#facilitate-web-crawlers"><i class="material-icons">link</i></a></h3><p translation-result="on">Google、Bing、Facebook、Twitter 和其它社交媒体网站都依赖网络爬虫去索引你的应用内容，并且让它的内容可以通过网络搜索到。</p><p translation-origin="off">Google, Bing, Facebook, Twitter, and other social media sites rely on web crawlers to index your application content and make that content searchable on the web.</p><p translation-result="on">这些网络爬虫可能不会像人类那样导航到你的具有高度交互性的 Angular 应用，并为其建立索引。</p><p translation-origin="off">These web crawlers may be unable to navigate and index your highly interactive Angular application as a human user could do.</p><p translation-result="on">Angular Universal 可以为你生成应用的静态版本，它易搜索、可链接，浏览时也不必借助 JavaScript。 它也让站点可以被预览，因为每个 URL 返回的都是一个完全渲染好的页面。</p><p translation-origin="off">Angular Universal can generate a static version of your app that is easily searchable, linkable, and navigable without JavaScript. Universal also makes a site preview available since each URL returns a fully rendered page.</p><p translation-result="on">启用对网络爬虫的支持通常也称作<a href="https://static.googleusercontent.com/media/www.google.com/en//webmasters/docs/search-engine-optimization-starter-guide.pdf">搜索引擎优化 (SEO)</a>。</p><p translation-origin="off">Enabling web crawlers is often referred to as <a href="https://static.googleusercontent.com/media/www.google.com/en//webmasters/docs/search-engine-optimization-starter-guide.pdf">search engine optimization (SEO)</a>.</p><a id="no-javascript"></a><h3 id="improve-performance-on-mobile-and-low-powered-devices" translation-result="on">提升手机和低功耗设备上的性能<a title="Link to this heading" class="header-link" aria-hidden="true" href="guide/universal#improve-performance-on-mobile-and-low-powered-devices"><i class="material-icons">link</i></a></h3><h3 translation-origin="off" id="improve-performance-on-mobile-and-low-powered-devices">Improve performance on mobile and low-powered devices<a title="Link to this heading" class="header-link" aria-hidden="true" href="guide/universal#improve-performance-on-mobile-and-low-powered-devices"><i class="material-icons">link</i></a></h3><p translation-result="on">有些设备不支持 JavaScript 或 JavaScript 执行得很差，导致用户体验不可接受。 对于这些情况，你可能会需要该应用的服务端渲染的、无 JavaScript 的版本。 虽然有一些限制，不过这个版本可能是那些完全没办法使用该应用的人的唯一选择。</p><p translation-origin="off">Some devices don't support JavaScript or execute JavaScript so poorly that the user experience is unacceptable. For these cases, you may require a server-rendered, no-JavaScript version of the app. This version, however limited, may be the only practical alternative for people who otherwise couldn't use the app at all.</p><a id="startup-performance"></a><h3 id="show-the-first-page-quickly" translation-result="on">快速显示第一页<a title="Link to this heading" class="header-link" aria-hidden="true" href="guide/universal#show-the-first-page-quickly"><i class="material-icons">link</i></a></h3><h3 translation-origin="off" id="show-the-first-page-quickly">Show the first page quickly<a title="Link to this heading" class="header-link" aria-hidden="true" href="guide/universal#show-the-first-page-quickly"><i class="material-icons">link</i></a></h3><p translation-result="on">快速显示第一页对于吸引用户是至关重要的。</p><p translation-origin="off">Displaying the first page quickly can be critical for user engagement.</p><p translation-result="on">如果页面加载超过了三秒钟，那么 <a href="https://www.doubleclickbygoogle.com/articles/mobile-speed-matters/">53% 的移动网站会被放弃</a>。 你的应用要启动得更快一点，以便在用户决定做别的事情之前吸引他们的注意力。</p><p translation-origin="off"><a href="https://www.thinkwithgoogle.com/marketing-resources/data-measurement/mobile-page-speed-new-industry-benchmarks/">53percent of mobile site visits are abandoned</a> if pages take longer than 3 seconds to load. Your app may have to launch faster to engage these users before they decide to do something else.</p><p translation-result="on">使用 Angular Universal，你可以为应用生成“着陆页”，它们看起来就和完整的应用一样。 这些着陆页是纯 HTML，并且即使 JavaScript 被禁用了也能显示。 这些页面不会处理浏览器事件，不过它们<em>可以</em>用 <code>[<a href="api/router/RouterLink" class="code-anchor">routerLink</a>](guide/router#router-link)</code> 在这个网站中导航。</p><p translation-origin="off">With Angular Universal, you can generate landing pages for the app that look like the complete app. The pages are pure HTML, and can display even if JavaScript is disabled. The pages don't handle browser events, but they <em>do</em> support navigation through the site using <a href="guide/router#router-link"><code>routerLink</code></a>.</p><p translation-result="on">在实践中，你可能要使用一个着陆页的静态版本来保持用户的注意力。 同时，你也会在幕后加载完整的 Angular 应用。 用户会觉得着陆页几乎是立即出现的，而当完整的应用加载完之后，又可以获得完整的交互体验。</p><p translation-origin="off">In practice, you'll serve a static version of the landing page to hold the user's attention. At the same time, you'll load the full Angular app behind it. The user perceives near-instant performance from the landing page and gets the full interactive experience after the full app loads.</p><a id="how-does-it-work"></a><h2 id="universal-web-servers" translation-result="on">Universal Web 服务器<a title="Link to this heading" class="header-link" aria-hidden="true" href="guide/universal#universal-web-servers"><i class="material-icons">link</i></a></h2><h2 translation-origin="off" id="universal-web-servers">Universal web servers<a title="Link to this heading" class="header-link" aria-hidden="true" href="guide/universal#universal-web-servers"><i class="material-icons">link</i></a></h2><p translation-result="on">Universal Web 服务器使用 <a href="guide/universal#universal-engine">Universal 模板引擎</a>渲染出的静态 HTML 来响应对应用页面的请求。 服务器接收并响应来自客户端（通常是浏览器）的 HTTP 请求，并回复静态文件，如脚本、CSS 和图片。 它可以直接响应数据请求，也可以作为独立数据服务器的代理进行响应。</p><p translation-origin="off">A Universal web server responds to application page requests with static HTML rendered by the <a href="guide/universal#universal-engine">Universal template engine</a>. The server receives and responds to HTTP requests from clients (usually browsers), and serves static assets such as scripts, CSS, and images. It may respond to data requests, either directly or as a proxy to a separate data server.</p><p translation-result="on">这个例子中的范例 Web 服务器是基于常见的 <a href="https://expressjs.com/">Express</a> 框架的。</p><p translation-origin="off">The sample web server for this guide is based on the popular <a href="https://expressjs.com/">Express</a> framework.</p><div class="alert is-helpful"><p translation-result="on"><strong>注意：</strong> <strong>任何一种</strong> Web 服务器技术都可以作为 Universal 应用的服务器，只要它能调用 Universal 的 <code><a href="api/platform-server/renderModuleFactory" class="code-anchor">renderModuleFactory</a>()</code> 函数。 这里所讨论的这些原则和决策点也适用于任何 Web 服务器技术。</p><p translation-origin="off"><strong>Note:</strong> <em>Any</em> web server technology can serve a Universal app as long as it can call Universal's <code><a href="api/platform-server/renderModuleFactory" class="code-anchor">renderModuleFactory</a>()</code> function. The principles and decision points discussed here apply to any web server technology.</p></div><p translation-result="on">要制作一个 Universal 应用，就要安装 <code>platform-server</code> 包，它提供了 DOM 的服务端实现、<code>XMLHttpRequest</code> 以及其它不依赖浏览器的底层特性。 使用 <code>platform-server</code> 模块（代替 <code>platform-browser</code> 模块）编译客户端应用，并在 Web 服务器上运行其生成的 Universal 应用。</p><p translation-origin="off">To make a Universal app, install the <code>platform-server</code> package, which provides server implementations of the DOM, <code>XMLHttpRequest</code>, and other low-level features that don't rely on a browser. Compile the client application with the <code>platform-server</code> module (instead of the <code>platform-browser</code> module) and run the resulting Universal app on a web server.</p><p translation-result="on">服务器（这个例子中使用的是 <a href="https://expressjs.com/">Node Express</a> 服务器）会把客户端对应用页面的请求传给 <code><a href="api/platform-server/renderModuleFactory" class="code-anchor">renderModuleFactory</a>()</code> 函数。</p><p translation-origin="off">The server (<a href="https://expressjs.com/">Node Express</a> in this guide's example) passes client requests for application pages to Universal's <code><a href="api/platform-server/renderModuleFactory" class="code-anchor">renderModuleFactory</a>()</code> function.</p><p translation-result="on"><code><a href="api/platform-server/renderModuleFactory" class="code-anchor">renderModuleFactory</a>()</code> 函数接受一个<em>模板</em> HTML 页面（通常是 <code>index.html</code>）、一个包含组件的 Angular <em>模块</em>和一个用于决定该显示哪些组件的<em>路由</em>作为输入。</p><p translation-origin="off">The <code><a href="api/platform-server/renderModuleFactory" class="code-anchor">renderModuleFactory</a>()</code> function takes as inputs a <em>template</em> HTML page (usually <code>index.html</code>), an Angular <em>module</em> containing components, and a <em>route</em> that determines which components to display.</p><p translation-result="on">该路由从客户端的请求中传给服务器。</p><p translation-origin="off">The route comes from the client's request to the server.</p><p translation-result="on">每次请求都会给出所请求路由的一个适当的视图。</p><p translation-origin="off">Each request results in the appropriate view for the requested route.</p><p translation-result="on"><code><a href="api/platform-server/renderModuleFactory" class="code-anchor">renderModuleFactory</a>()</code> 在模板中的 <code>&lt;app&gt;</code> 标记中渲染出这个视图，并为客户端创建一个完成的 HTML 页面。</p><p translation-origin="off">The <code><a href="api/platform-server/renderModuleFactory" class="code-anchor">renderModuleFactory</a>()</code> function renders the view within the <code>&lt;app&gt;</code> tag of the template, creating a finished HTML page for the client.</p><p translation-result="on">最后，服务器就会把渲染好的页面返回给客户端。</p><p translation-origin="off">Finally, the server returns the rendered page to the client.</p><a id="summary"></a><h2 id="preparing-for-server-side-rendering" translation-result="on">准备服务端渲染<a title="Link to this heading" class="header-link" aria-hidden="true" href="guide/universal#preparing-for-server-side-rendering"><i class="material-icons">link</i></a></h2><h2 translation-origin="off" id="preparing-for-server-side-rendering">Preparing for server-side rendering<a title="Link to this heading" class="header-link" aria-hidden="true" href="guide/universal#preparing-for-server-side-rendering"><i class="material-icons">link</i></a></h2><p translation-result="on">要想让应用可以在服务器上渲染，就要对应用自身做一些修改，然后搭建服务器环境。</p><p translation-origin="off">Before your app can be rendered on a server, you must make changes in the app itself, and also set up the server.</p><ol><li><p translation-result="on">安装依赖。</p><p translation-origin="off">Install dependencies.</p></li><li><p translation-result="on">通过修改应用代码及其配置进行准备。</p><p translation-origin="off">Prepare your app by modifying both the app code and its configuration.</p></li><li><p translation-result="on">添加构建目标，并使用 CLI 中的 <code>@nguniversal/express-engine</code> 原理图来构建出 Universal 包。</p><p translation-origin="off">Add a build target, and build a Universal bundle using the CLI with the <code>@nguniversal/express-engine</code> schematic.</p></li><li><p translation-result="on">设置服务器，以运行 Universal 包。</p><p translation-origin="off">Set up a server to run Universal bundles.</p></li><li><p translation-result="on">打包并在服务器上运行此应用。</p><p translation-origin="off">Pack and run the app on the server.</p></li></ol><p translation-result="on">下面各节将会更详细的介绍这些主要步骤。</p><p translation-origin="off">The following sections go into each of these main steps in more detail.</p><div class="alert is-helpful"><p translation-result="on"><strong>注意：稍后的 </strong><a href="guide/universal#the-example">Universal 教程</a>将引导你基于 "英雄指南" 应用来完成各个步骤，并详细介绍你能做什么以及为什么要那么做。</p><p translation-origin="off"><strong>Note:</strong> The <a href="guide/universal#the-example">Universal tutorial</a> below walks you through the steps using the Tour of Heroes sample app, and goes into more detail about what you can do and why you might want to do it.</p><p translation-result="on">要亲自体验带服务端渲染功能的应用，请把 <a href="https://github.com/angular/universal-starter">Angular Universal starter</a> 克隆下来试试。</p><p translation-origin="off">To see a working version of an app with server-side rendering, clone the <a href="https://github.com/angular/universal-starter">Angular Universal starter</a>.</p></div><div class="callout is-critical"><header translation-result="on">服务端请求的安全性</header><header translation-origin="off">Security for server requests</header><p translation-result="on">应用从浏览器上发出的请求和从服务器上发出的请求是不同的。 Universal 的 HTTP 请求有不同的安全需求。</p><p translation-origin="off">HTTP requests issued from a browser app aren't the same as those issued by the Universal app on the server. Universal HTTP requests have different security requirements</p><p translation-result="on">当浏览器发出 HTTP 请求时，服务器处理时会具有一些假设，比如 Cookie、XSRF 头等等。 例如，浏览器会自动发送当前用户的认证 Cookie。 Angular Universal 却没办法把这些凭证转发给独立的数据服务器。 如果你的服务器要处理 HTTP 请求，你必须另行添加自己的通道来提供安全性。</p><p translation-origin="off">When a browser makes an HTTP request, the server can make assumptions about cookies, XSRF headers, and so on. For example, the browser automatically sends authentication cookies for the current user. Angular Universal can't forward these credentials to a separate data server. If your server handles HTTP requests, you'll have to add your own security plumbing.</p></div><h2 id="step-1-install-dependencies" translation-result="on">步骤一：安装依赖<a title="Link to this heading" class="header-link" aria-hidden="true" href="guide/universal#step-1-install-dependencies"><i class="material-icons">link</i></a></h2><h2 translation-origin="off" id="step-1-install-dependencies">Step 1: Install dependencies<a title="Link to this heading" class="header-link" aria-hidden="true" href="guide/universal#step-1-install-dependencies"><i class="material-icons">link</i></a></h2><p translation-result="on">把 <code>@angular/platform-server</code> 安装到项目中。在项目中使用与其它 <code>@angular</code> 包相同的版本。你还需要 <code>ts-loader</code> 供 Webpack 构建时使用，还要安装 <code>@nguniversal/module-map-ngfactory-loader</code> 来处理服务端渲染环境下的惰性加载。</p><p translation-origin="off">Install <code>@angular/platform-server</code> into your project. Use the same version as the other <code>@angular</code> packages in your project. You also need <code>ts-loader</code>, <code>webpack-cli</code> for your webpack build and <code>@nguniversal/module-map-ngfactory-loader</code> to handle lazy-loading in the context of a server-render.</p><code-example language="sh" class="code-shell" ng-version="7.0.0"><div style="display:none">$ npm install --save @angular/platform-server @nguniversal/module-map-ngfactory-loader ts-loader webpack-cli</div><aio-code><pre class="prettyprint lang-sh">      <button class="material-icons copy-button no-print ng-star-inserted" title="Copy code snippet" aria-label="">
        <span aria-hidden="true">content_copy</span>
      </button>
      <code class="animated fadeIn"><span class="pln">$ npm install </span><span class="pun">--</span><span class="pln">save </span><span class="lit">@angular</span><span class="pun">/</span><span class="pln">platform</span><span class="pun">-</span><span class="pln">server </span><span class="lit">@nguniversal</span><span class="pun">/</span><span class="pln">module</span><span class="pun">-</span><span class="pln">map</span><span class="pun">-</span><span class="pln">ngfactory</span><span class="pun">-</span><span class="pln">loader ts</span><span class="pun">-</span><span class="pln">loader webpack</span><span class="pun">-</span><span class="pln">cli</span></code>
    </pre></aio-code></code-example><h2 id="step-2-prepare-your-app" translation-result="on">步骤二：准备你的应用<a title="Link to this heading" class="header-link" aria-hidden="true" href="guide/universal#step-2-prepare-your-app"><i class="material-icons">link</i></a></h2><h2 translation-origin="off" id="step-2-prepare-your-app">Step 2: Prepare your app<a title="Link to this heading" class="header-link" aria-hidden="true" href="guide/universal#step-2-prepare-your-app"><i class="material-icons">link</i></a></h2><p translation-result="on">要让你的应用为 Universal 渲染做好准备，要遵循如下步骤：</p><p translation-origin="off">To prepare your app for Universal rendering, take the following steps:</p><ul><li><p translation-result="on">为应用添加 Universal 支持。</p><p translation-origin="off">Add Universal support to your app.</p></li><li><p translation-result="on">创建服务端根模块。</p><p translation-origin="off">Create a server root module.</p></li><li><p translation-result="on">创建一个 main 文件，以导出服务端根模块。</p><p translation-origin="off">Create a main file to export the server root module.</p></li><li><p translation-result="on">配置服务端根模块。</p><p translation-origin="off">Configure the server root module.</p></li></ul><h3 id="2a-add-universal-support-to-your-app" translation-result="on">2a. 为应用添加 Universal 支持<a title="Link to this heading" class="header-link" aria-hidden="true" href="guide/universal#2a-add-universal-support-to-your-app"><i class="material-icons">link</i></a></h3><h3 translation-origin="off" id="2a-add-universal-support-to-your-app">2a. Add Universal support to your app<a title="Link to this heading" class="header-link" aria-hidden="true" href="guide/universal#2a-add-universal-support-to-your-app"><i class="material-icons">link</i></a></h3><p translation-result="on">要想让你的 <code>AppModule</code> 与 Universal 兼容，就要在 <code>src/app/app.module.ts</code> 中导入时 <code><a href="api/platform-browser/BrowserModule" class="code-anchor">BrowserModule</a></code> 添加一个 <code>.withServerTransition()</code> 并带上应用的 ID。</p><p translation-origin="off">Make your <code>AppModule</code> compatible with Universal by adding <code>.withServerTransition()</code> and an application ID to your <code><a href="api/platform-browser/BrowserModule" class="code-anchor">BrowserModule</a></code> import in <code>src/app/app.module.ts</code>.</p><code-example format="." language="typescript" linenums="false" ng-version="7.0.0"><div style="display:none">@<a href="api/core/NgModule" class="code-anchor">NgModule</a>({ <a href="api/core/NgModule#bootstrap" class="code-anchor">bootstrap</a>: [AppComponent], <a href="api/core/NgModule#imports" class="code-anchor">imports</a>: [ // Add .withServerTransition() to support Universal rendering. // The application ID can be any identifier which is unique on // the page. BrowserModule.withServerTransition({appId: 'my-app'}), ... ], }) export class AppModule {}</div><aio-code><pre class="prettyprint lang-typescript">      <button class="material-icons copy-button no-print ng-star-inserted" title="Copy code snippet" aria-label="">
        <span aria-hidden="true">content_copy</span>
      </button>
      <code class="animated fadeIn"><span class="lit">@</span><a href="api/core/NgModule" class="code-anchor"><span class="lit">NgModule</span></a><span class="pun">({</span><span class="pln">
  </span><a href="api/core/NgModule#bootstrap" class="code-anchor"><span class="pln">bootstrap</span></a><span class="pun">:</span><span class="pln"> </span><span class="pun">[</span><span class="typ">AppComponent</span><span class="pun">],</span><span class="pln">
  </span><a href="api/core/NgModule#imports" class="code-anchor"><span class="pln">imports</span></a><span class="pun">:</span><span class="pln"> </span><span class="pun">[</span><span class="pln">
    </span><span class="com">// Add .withServerTransition() to support Universal rendering.</span><span class="pln">
    </span><span class="com">// The application ID can be any identifier which is unique on</span><span class="pln">
    </span><span class="com">// the page.</span><span class="pln">
    </span><span class="typ">BrowserModule</span><span class="pun">.</span><span class="pln">withServerTransition</span><span class="pun">({</span><span class="pln">appId</span><span class="pun">:</span><span class="pln"> </span><span class="str">'my-app'</span><span class="pun">}),</span><span class="pln">
    </span><span class="pun">...</span><span class="pln">
  </span><span class="pun">],</span><span class="pln">

</span><span class="pun">})</span><span class="pln">
</span><span class="kwd">export</span><span class="pln"> </span><span class="kwd">class</span><span class="pln"> </span><span class="typ">AppModule</span><span class="pln"> </span><span class="pun">{}</span></code>
    </pre></aio-code></code-example><h3 id="2b-create-a-server-root-module" translation-result="on">2b. 创建服务端根模块<a title="Link to this heading" class="header-link" aria-hidden="true" href="guide/universal#2b-create-a-server-root-module"><i class="material-icons">link</i></a></h3><h3 translation-origin="off" id="2b-create-a-server-root-module">2b. Create a server root module<a title="Link to this heading" class="header-link" aria-hidden="true" href="guide/universal#2b-create-a-server-root-module"><i class="material-icons">link</i></a></h3><p translation-result="on">在服务器上运行时，要创建一个名叫 <code>AppServerModule</code> 的模块作为根模块。这个例子中把它放在了 <code>app.module.ts</code> 附近的 <code>app.server.module.ts</code> 文件中。这个新模块从 <code>AppModule</code> 中导入了所有东西，并且导入了 <code><a href="api/platform-server/ServerModule" class="code-anchor">ServerModule</a></code>。它还添加了 <code>ModuleMapLoaderModule</code> 以便在通过 Angular CLI 进行服务端渲染时也能使用惰性加载路由。</p><p translation-origin="off">Create a module named <code>AppServerModule</code> to act as the root module when running on the server. This example places it alongside <code>app.module.ts</code> in a file named <code>app.server.module.ts</code>. The new module imports everything from the root <code>AppModule</code>, and adds <code><a href="api/platform-server/ServerModule" class="code-anchor">ServerModule</a></code>. It also adds <code>ModuleMapLoaderModule</code> to help make lazy-loaded routes possible during server-side renders with the Angular CLI.</p><p translation-result="on">下面是 <code>src/app/app.server.module.ts</code> 的例子。</p><p translation-origin="off">Here's an example in <code>src/app/app.server.module.ts</code>.</p><code-example format="." language="typescript" linenums="false" ng-version="7.0.0"><div style="display:none">import {<a href="api/core/NgModule" class="code-anchor">NgModule</a>} from '@angular/core'; import {<a href="api/platform-server/ServerModule" class="code-anchor">ServerModule</a>} from '@angular/platform-server'; import {ModuleMapLoaderModule} from '@nguniversal/module-map-ngfactory-loader'; import {AppModule} from './app.module'; import {AppComponent} from './app.component'; @<a href="api/core/NgModule" class="code-anchor">NgModule</a>({ <a href="api/core/NgModule#imports" class="code-anchor">imports</a>: [ // The AppServerModule should import your AppModule followed // by the <a href="api/platform-server/ServerModule" class="code-anchor">ServerModule</a> from @angular/platform-server. AppModule, <a href="api/platform-server/ServerModule" class="code-anchor">ServerModule</a>, ModuleMapLoaderModule // &lt;-- *<a href="api/core/RendererStyleFlags2#Important" class="code-anchor">Important</a>* to have lazy-loaded routes work ], // Since the bootstrapped component is not inherited from your // imported AppModule, it needs to be repeated here. <a href="api/core/NgModule#bootstrap" class="code-anchor">bootstrap</a>: [AppComponent], }) export class AppServerModule {}</div><aio-code><pre class="prettyprint lang-typescript">      <button class="material-icons copy-button no-print ng-star-inserted" title="Copy code snippet" aria-label="">
        <span aria-hidden="true">content_copy</span>
      </button>
      <code class="animated fadeIn"><span class="kwd">import</span><span class="pln"> </span><span class="pun">{</span><a href="api/core/NgModule" class="code-anchor"><span class="typ">NgModule</span></a><span class="pun">}</span><span class="pln"> from </span><span class="str">'@angular/core'</span><span class="pun">;</span><span class="pln">
</span><span class="kwd">import</span><span class="pln"> </span><span class="pun">{</span><a href="api/platform-server/ServerModule" class="code-anchor"><span class="typ">ServerModule</span></a><span class="pun">}</span><span class="pln"> from </span><span class="str">'@angular/platform-server'</span><span class="pun">;</span><span class="pln">
</span><span class="kwd">import</span><span class="pln"> </span><span class="pun">{</span><span class="typ">ModuleMapLoaderModule</span><span class="pun">}</span><span class="pln"> from </span><span class="str">'@nguniversal/module-map-ngfactory-loader'</span><span class="pun">;</span><span class="pln">

</span><span class="kwd">import</span><span class="pln"> </span><span class="pun">{</span><span class="typ">AppModule</span><span class="pun">}</span><span class="pln"> from </span><span class="str">'./app.module'</span><span class="pun">;</span><span class="pln">
</span><span class="kwd">import</span><span class="pln"> </span><span class="pun">{</span><span class="typ">AppComponent</span><span class="pun">}</span><span class="pln"> from </span><span class="str">'./app.component'</span><span class="pun">;</span><span class="pln">

</span><span class="lit">@</span><a href="api/core/NgModule" class="code-anchor"><span class="lit">NgModule</span></a><span class="pun">({</span><span class="pln">
  </span><a href="api/core/NgModule#imports" class="code-anchor"><span class="pln">imports</span></a><span class="pun">:</span><span class="pln"> </span><span class="pun">[</span><span class="pln">
    </span><span class="com">// The AppServerModule should import your AppModule followed</span><span class="pln">
    </span><span class="com">// by the </span><a href="api/platform-server/ServerModule" class="code-anchor"><span class="com">ServerModule</span></a><span class="com"> from @angular/platform-server.</span><span class="pln">
    </span><span class="typ">AppModule</span><span class="pun">,</span><span class="pln">
    </span><a href="api/platform-server/ServerModule" class="code-anchor"><span class="typ">ServerModule</span></a><span class="pun">,</span><span class="pln">
    </span><span class="typ">ModuleMapLoaderModule</span><span class="pln"> </span><span class="com">// &lt;-- *</span><a href="api/core/RendererStyleFlags2#Important" class="code-anchor"><span class="com">Important</span></a><span class="com">* to have lazy-loaded routes work</span><span class="pln">
  </span><span class="pun">],</span><span class="pln">
  </span><span class="com">// Since the bootstrapped component is not inherited from your</span><span class="pln">
  </span><span class="com">// imported AppModule, it needs to be repeated here.</span><span class="pln">
  </span><a href="api/core/NgModule#bootstrap" class="code-anchor"><span class="pln">bootstrap</span></a><span class="pun">:</span><span class="pln"> </span><span class="pun">[</span><span class="typ">AppComponent</span><span class="pun">],</span><span class="pln">
</span><span class="pun">})</span><span class="pln">
</span><span class="kwd">export</span><span class="pln"> </span><span class="kwd">class</span><span class="pln"> </span><span class="typ">AppServerModule</span><span class="pln"> </span><span class="pun">{}</span></code>
    </pre></aio-code></code-example><h3 id="2c-create-a-main-file-to-export-appservermodule" translation-result="on">2c. 创建一个 main 文件，导出 AppServerModule<a title="Link to this heading" class="header-link" aria-hidden="true" href="guide/universal#2c-create-a-main-file-to-export-appservermodule"><i class="material-icons">link</i></a></h3><h3 translation-origin="off" id="2c-create-a-main-file-to-export-appservermodule">2c. Create a main file to export AppServerModule<a title="Link to this heading" class="header-link" aria-hidden="true" href="guide/universal#2c-create-a-main-file-to-export-appservermodule"><i class="material-icons">link</i></a></h3><p translation-result="on">在应用的 <code>src/</code> 目录下为你的 Universal 包创建一个 main 文件，以导出 <code>AppServerModule</code> 实例。在这个例子里它叫 <code>main.server.ts</code>。</p><p translation-origin="off">Create a main file for your Universal bundle in the app <code>src/</code> folder to export your <code>AppServerModule</code> instance. This example calls the file <code>main.server.ts</code>.</p><code-example format="." language="typescript" linenums="false" ng-version="7.0.0"><div style="display:none">export { AppServerModule } from './app/app.server.module';</div><aio-code><pre class="prettyprint lang-typescript">      <button class="material-icons copy-button no-print ng-star-inserted" title="Copy code snippet" aria-label="">
        <span aria-hidden="true">content_copy</span>
      </button>
      <code class="animated fadeIn"><span class="kwd">export</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><span class="typ">AppServerModule</span><span class="pln"> </span><span class="pun">}</span><span class="pln"> from </span><span class="str">'./app/app.server.module'</span><span class="pun">;</span></code>
    </pre></aio-code></code-example><h3 id="2d-create-a-configuration-file-for-appservermodule" translation-result="on">2d. 为 AppServerModule 创建配置文件<a title="Link to this heading" class="header-link" aria-hidden="true" href="guide/universal#2d-create-a-configuration-file-for-appservermodule"><i class="material-icons">link</i></a></h3><h3 translation-origin="off" id="2d-create-a-configuration-file-for-appservermodule">2d. Create a configuration file for AppServerModule<a title="Link to this heading" class="header-link" aria-hidden="true" href="guide/universal#2d-create-a-configuration-file-for-appservermodule"><i class="material-icons">link</i></a></h3><p translation-result="on">把 <code>tsconfig.app.json</code> 复制到 <code>tsconfig.server.json</code> 中，并做如下修改：</p><p translation-origin="off">Copy <code>tsconfig.app.json</code> to <code>tsconfig.server.json</code> and modify it as follows:</p><ul><li><p translation-result="on">在 <code>"compilerOptions"</code> 中，把 <code>"module"</code> 改为 <code>"commonjs"</code>。</p><p translation-origin="off">In <code>"compilerOptions"</code>, set the <code>"module"</code> target to <code>"commonjs"</code>.</p></li><li><p translation-result="on">添加一个 <code>"angularCompilerOptions"</code> 节，并把 <code>"entryModule"</code>（入口模块）指向你的 <code>AppServerModule</code> 实例，格式为 <code>importPath#symbolName</code>。在这个例子中，这个入口模块是 <code>app/app.server.module#AppServerModule</code>。</p><p translation-origin="off">Add a section for <code>"angularCompilerOptions"</code> and set <code>"entryModule"</code> to point to your <code>AppServerModule</code> instance. Use the format <code>importPath#symbolName</code>. In this example, the entry module is <code>app/app.server.module#AppServerModule</code>.</p></li></ul><code-example format="." language="none" linenums="false" ng-version="7.0.0"><div style="display:none">{ "extends": "../tsconfig.json", "compilerOptions": { "outDir": "../out-tsc/app", "baseUrl": "./", // Set the module format to "commonjs": "module": "commonjs", "types": [] }, "exclude": [ "test.ts", "**/*.spec.ts" ], // Add "angularCompilerOptions" with the AppServerModule you wrote // set as the "entryModule". "angularCompilerOptions": { "entryModule": "app/app.server.module#AppServerModule" } }</div><aio-code><pre class="prettyprint lang-none">      <button class="material-icons copy-button no-print ng-star-inserted" title="Copy code snippet" aria-label="">
        <span aria-hidden="true">content_copy</span>
      </button>
      <code class="animated fadeIn"><span class="pun">{</span><span class="pln">
  </span><span class="str">"extends"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"../tsconfig.json"</span><span class="pun">,</span><span class="pln">
  </span><span class="str">"compilerOptions"</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="str">"outDir"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"../out-tsc/app"</span><span class="pun">,</span><span class="pln">
    </span><span class="str">"baseUrl"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"./"</span><span class="pun">,</span><span class="pln">
    </span><span class="com">// Set the module format to "commonjs":</span><span class="pln">
    </span><span class="str">"module"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"commonjs"</span><span class="pun">,</span><span class="pln">
    </span><span class="str">"types"</span><span class="pun">:</span><span class="pln"> </span><span class="pun">[]</span><span class="pln">
  </span><span class="pun">},</span><span class="pln">
  </span><span class="str">"exclude"</span><span class="pun">:</span><span class="pln"> </span><span class="pun">[</span><span class="pln">
    </span><span class="str">"test.ts"</span><span class="pun">,</span><span class="pln">
    </span><span class="str">"**/*.spec.ts"</span><span class="pln">
  </span><span class="pun">],</span><span class="pln">
  </span><span class="com">// Add "angularCompilerOptions" with the AppServerModule you wrote</span><span class="pln">
  </span><span class="com">// set as the "entryModule".</span><span class="pln">
  </span><span class="str">"angularCompilerOptions"</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="str">"entryModule"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"app/app.server.module#AppServerModule"</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span></code>
    </pre></aio-code></code-example><h2 id="step-3-create-a-new-build-target-and-build-the-bundle" translation-result="on">步骤三：创建新的构建目标，并打包<a title="Link to this heading" class="header-link" aria-hidden="true" href="guide/universal#step-3-create-a-new-build-target-and-build-the-bundle"><i class="material-icons">link</i></a></h2><h2 translation-origin="off" id="step-3-create-a-new-build-target-and-build-the-bundle">Step 3: Create a new build target and build the bundle<a title="Link to this heading" class="header-link" aria-hidden="true" href="guide/universal#step-3-create-a-new-build-target-and-build-the-bundle"><i class="material-icons">link</i></a></h2><p translation-result="on">打开本项目的 Angular 配置文件 <code>angular.json</code>，并在 <code>"architect"</code> 节下添加一个新的目标。下面的例子中把这个新目标命名为 <code>"server"</code>。</p><p translation-origin="off">Open the Angular configuration file, <code>angular.json</code>, for your project, and add a new target in the <code>"architect"</code> section for the server build. The following example names the new target <code>"server"</code>.</p><code-example format="." language="none" linenums="false" ng-version="7.0.0"><div style="display:none">"architect": { "build": { ... } "server": { "builder": "@angular-devkit/build-angular:server", "options": { "outputPath": "dist/my-project-server", "main": "src/main.server.ts", "tsConfig": "src/tsconfig.server.json" } } }</div><aio-code><pre class="prettyprint lang-none">      <button class="material-icons copy-button no-print ng-star-inserted" title="Copy code snippet" aria-label="">
        <span aria-hidden="true">content_copy</span>
      </button>
      <code class="animated fadeIn"><span class="str">"architect"</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="str">"build"</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><span class="pun">...</span><span class="pln"> </span><span class="pun">}</span><span class="pln">
  </span><span class="str">"server"</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="str">"builder"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"@angular-devkit/build-angular:server"</span><span class="pun">,</span><span class="pln">
    </span><span class="str">"options"</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      </span><span class="str">"outputPath"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"dist/my-project-server"</span><span class="pun">,</span><span class="pln">
      </span><span class="str">"main"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"src/main.server.ts"</span><span class="pun">,</span><span class="pln">
      </span><span class="str">"tsConfig"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"src/tsconfig.server.json"</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span></code>
    </pre></aio-code></code-example><p translation-result="on">要想为应用程序构建服务包，请使用 <code>ng run</code> 命令，格式为 <code>projectName#serverTarget</code>。在这个例子中，目前已配置了两个目标 <code>"build"</code> 和 <code>"server"</code>。</p><p translation-origin="off">To build a server bundle for your application, use the <code>ng run</code> command, with the format <code>projectName#serverTarget</code>. In our example, there are now two targets configured, <code>"build"</code> and <code>"server"</code>.</p><code-example format="." language="none" linenums="false" ng-version="7.0.0"><div style="display:none"># This builds your project using the server <a href="api/router/RouterLinkWithHref#target" class="code-anchor">target</a>, and places the output # in dist/my-project-server/ $ ng run my-project:server Date: 2017-07-24T22:42:09.739Z Hash: 9cac7d8e9434007fd8da <a href="api/common/Time" class="code-anchor">Time</a>: 4933ms chunk {0} main.js (main) 9.49 kB [entry] [rendered] chunk {1} styles.css (styles) 0 bytes [entry] [rendered]</div><aio-code><pre class="prettyprint lang-none">      <button class="material-icons copy-button no-print ng-star-inserted" title="Copy code snippet" aria-label="">
        <span aria-hidden="true">content_copy</span>
      </button>
      <code class="animated fadeIn"><span class="com"># This builds your project using the server </span><a href="api/router/RouterLinkWithHref#target" class="code-anchor"><span class="com">target</span></a><span class="com">, and places the output</span><span class="pln">
</span><span class="com"># in dist/my-project-server/</span><span class="pln">
$ ng run </span><span class="kwd">my</span><span class="pun">-</span><span class="pln">project</span><span class="pun">:</span><span class="pln">server

</span><span class="typ">Date</span><span class="pun">:</span><span class="pln"> </span><span class="lit">2017</span><span class="pun">-</span><span class="lit">07</span><span class="pun">-</span><span class="lit">24T22</span><span class="pun">:</span><span class="lit">42</span><span class="pun">:</span><span class="lit">09.739Z</span><span class="pln">
</span><span class="typ">Hash</span><span class="pun">:</span><span class="pln"> </span><span class="lit">9cac7d8e9434007fd8da</span><span class="pln">
</span><a href="api/common/Time" class="code-anchor"><span class="typ">Time</span></a><span class="pun">:</span><span class="pln"> </span><span class="lit">4933ms</span><span class="pln">
chunk </span><span class="pun">{</span><span class="lit">0</span><span class="pun">}</span><span class="pln"> main</span><span class="pun">.</span><span class="pln">js </span><span class="pun">(</span><span class="pln">main</span><span class="pun">)</span><span class="pln"> </span><span class="lit">9.49</span><span class="pln"> kB </span><span class="pun">[</span><span class="pln">entry</span><span class="pun">]</span><span class="pln"> </span><span class="pun">[</span><span class="pln">rendered</span><span class="pun">]</span><span class="pln">
chunk </span><span class="pun">{</span><span class="lit">1</span><span class="pun">}</span><span class="pln"> styles</span><span class="pun">.</span><span class="pln">css </span><span class="pun">(</span><span class="pln">styles</span><span class="pun">)</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> bytes </span><span class="pun">[</span><span class="pln">entry</span><span class="pun">]</span><span class="pln"> </span><span class="pun">[</span><span class="pln">rendered</span><span class="pun">]</span></code>
    </pre></aio-code></code-example><h2 id="step-4-set-up-a-server-to-run-universal-bundles" translation-result="on">步骤四：设置服务器环境，以运行 Universal 包<a title="Link to this heading" class="header-link" aria-hidden="true" href="guide/universal#step-4-set-up-a-server-to-run-universal-bundles"><i class="material-icons">link</i></a></h2><h2 translation-origin="off" id="step-4-set-up-a-server-to-run-universal-bundles">Step 4: Set up a server to run Universal bundles<a title="Link to this heading" class="header-link" aria-hidden="true" href="guide/universal#step-4-set-up-a-server-to-run-universal-bundles"><i class="material-icons">link</i></a></h2><p translation-result="on">要想运行 Universal 包，你需要把它发送给服务器。</p><p translation-origin="off">To run a Universal bundle, you need to send it to a server.</p><p translation-result="on">下面的例子中把 <code>AppServerModule</code>（用 AOT 编译的）传给了 <code>PlatformServer</code> 的 <code><a href="api/platform-server/renderModuleFactory" class="code-anchor">renderModuleFactory</a>()</code>，它会序列化该应用，并把结果返回给浏览器。</p><p translation-origin="off">The following example passes <code>AppServerModule</code> (compiled with AoT) to the <code>PlatformServer</code> method <code><a href="api/platform-server/renderModuleFactory" class="code-anchor">renderModuleFactory</a>()</code>, which serializes the app and returns the result to the browser.</p><code-example format="." language="typescript" linenums="false" ng-version="7.0.0"><div style="display:none">app.engine('html', (_, options, callback) =&gt; { <a href="api/platform-server/renderModuleFactory" class="code-anchor">renderModuleFactory</a>(AppServerModuleNgFactory, { // Our index.html <a href="api/platform-server/PlatformConfig#document" class="code-anchor">document</a>: <a href="api/core/Component#template" class="code-anchor">template</a>, url: options.req.url, // configure DI to make lazy-loading work differently // (we need to instantly render the view) extraProviders: [ provideModuleMap(LAZY_MODULE_MAP) ] }).then(html =&gt; { callback(null, html); }); });</div><aio-code><pre class="prettyprint lang-typescript">      <button class="material-icons copy-button no-print ng-star-inserted" title="Copy code snippet" aria-label="">
        <span aria-hidden="true">content_copy</span>
      </button>
      <code class="animated fadeIn"><span class="pln">app</span><span class="pun">.</span><span class="pln">engine</span><span class="pun">(</span><span class="str">'html'</span><span class="pun">,</span><span class="pln"> </span><span class="pun">(</span><span class="pln">_</span><span class="pun">,</span><span class="pln"> options</span><span class="pun">,</span><span class="pln"> callback</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><a href="api/platform-server/renderModuleFactory" class="code-anchor"><span class="pln">renderModuleFactory</span></a><span class="pun">(</span><span class="typ">AppServerModuleNgFactory</span><span class="pun">,</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="com">// Our index.html</span><span class="pln">
    </span><a href="api/platform-server/PlatformConfig#document" class="code-anchor"><span class="pln">document</span></a><span class="pun">:</span><span class="pln"> </span><a href="api/core/Component#template" class="code-anchor"><span class="pln">template</span></a><span class="pun">,</span><span class="pln">
    url</span><span class="pun">:</span><span class="pln"> options</span><span class="pun">.</span><span class="pln">req</span><span class="pun">.</span><span class="pln">url</span><span class="pun">,</span><span class="pln">
    </span><span class="com">// configure DI to make lazy-loading work differently</span><span class="pln">
    </span><span class="com">// (we need to instantly render the view)</span><span class="pln">
    extraProviders</span><span class="pun">:</span><span class="pln"> </span><span class="pun">[</span><span class="pln">
      provideModuleMap</span><span class="pun">(</span><span class="pln">LAZY_MODULE_MAP</span><span class="pun">)</span><span class="pln">
    </span><span class="pun">]</span><span class="pln">
  </span><span class="pun">}).</span><span class="pln">then</span><span class="pun">(</span><span class="pln">html </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    callback</span><span class="pun">(</span><span class="kwd">null</span><span class="pun">,</span><span class="pln"> html</span><span class="pun">);</span><span class="pln">
  </span><span class="pun">});</span><span class="pln">
</span><span class="pun">});</span></code>
    </pre></aio-code></code-example><p translation-result="on">该技术为你提供了完全的灵活性。方便起见，你还可以使用具有一些内置功能的 <code>@nguniversal/express-engine</code> 工具。</p><p translation-origin="off">This technique gives you complete flexibility. For convenience, you can also use the <code>@nguniversal/express-engine</code> tool that has some built-in features.</p><code-example format="." language="typescript" linenums="false" ng-version="7.0.0"><div style="display:none">import { ngExpressEngine } from '@nguniversal/express-engine'; app.engine('html', ngExpressEngine({ <a href="api/core/NgModule#bootstrap" class="code-anchor">bootstrap</a>: AppServerModuleNgFactory, providers: [ provideModuleMap(LAZY_MODULE_MAP) ] }));</div><aio-code><pre class="prettyprint lang-typescript">      <button class="material-icons copy-button no-print ng-star-inserted" title="Copy code snippet" aria-label="">
        <span aria-hidden="true">content_copy</span>
      </button>
      <code class="animated fadeIn"><span class="kwd">import</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> ngExpressEngine </span><span class="pun">}</span><span class="pln"> from </span><span class="str">'@nguniversal/express-engine'</span><span class="pun">;</span><span class="pln">

app</span><span class="pun">.</span><span class="pln">engine</span><span class="pun">(</span><span class="str">'html'</span><span class="pun">,</span><span class="pln"> ngExpressEngine</span><span class="pun">({</span><span class="pln">
  </span><a href="api/core/NgModule#bootstrap" class="code-anchor"><span class="pln">bootstrap</span></a><span class="pun">:</span><span class="pln"> </span><span class="typ">AppServerModuleNgFactory</span><span class="pun">,</span><span class="pln">
  providers</span><span class="pun">:</span><span class="pln"> </span><span class="pun">[</span><span class="pln">
    provideModuleMap</span><span class="pun">(</span><span class="pln">LAZY_MODULE_MAP</span><span class="pun">)</span><span class="pln">
  </span><span class="pun">]</span><span class="pln">
</span><span class="pun">}));</span></code>
    </pre></aio-code></code-example><p translation-result="on">下面的简单例子实现了一个骨架级 Node Express 服务器来解决这些问题。 （注意，它只能用于演示，在实际生产环境中，你还要设置身份验证和安全性。）</p><p translation-origin="off">The following simple example implements a bare-bones Node Express server to fire everything up. (Note that this is for demonstration only. In a real production environment, you need to set up additional authentication and security.)</p><p translation-result="on">在应用的根目录下，紧挨着 <code>package.json</code>，创建一个名叫 <code>server.ts</code> 的文件，并添加如下内容。</p><p translation-origin="off">At the root level of your project, next to <code>package.json</code>, create a file named <code>server.ts</code> and add the following content.</p><code-example format="." language="typescript" linenums="false" ng-version="7.0.0"><div style="display:none">// These are important and needed before anything else import 'zone.js/dist/zone-node'; import 'reflect-metadata'; import { <a href="api/platform-server/renderModuleFactory" class="code-anchor">renderModuleFactory</a> } from '@angular/platform-server'; import { <a href="api/core/enableProdMode" class="code-anchor">enableProdMode</a> } from '@angular/core'; import { provideModuleMap } from '@nguniversal/module-map-ngfactory-loader'; import * as express from 'express'; import { join } from 'path'; import { readFileSync } from 'fs'; // Faster server renders w/ Prod mode (dev mode never needed) <a href="api/core/enableProdMode" class="code-anchor">enableProdMode</a>(); // Express server const app = express(); const PORT = process.env.PORT || 4000; const DIST_FOLDER = join(process.cwd(), 'dist'); // Our index.html we'll use as our <a href="api/core/Component#template" class="code-anchor">template</a> const <a href="api/core/Component#template" class="code-anchor">template</a> = readFileSync(join(DIST_FOLDER, '<a href="api/animations/browser" class="code-anchor">browser</a>', 'index.html')).toString(); const { AppServerModuleNgFactory, LAZY_MODULE_MAP } = require('./server/main'); app.engine('html', (_, options, callback) =&gt; { <a href="api/platform-server/renderModuleFactory" class="code-anchor">renderModuleFactory</a>(AppServerModuleNgFactory, { // Our index.html <a href="api/platform-server/PlatformConfig#document" class="code-anchor">document</a>: <a href="api/core/Component#template" class="code-anchor">template</a>, url: options.req.url, // DI so that we can get lazy-loading to work differently (since we need it to just instantly render it) extraProviders: [ provideModuleMap(LAZY_MODULE_MAP) ] }).then(html =&gt; { callback(null, html); }); }); app.set('view engine', 'html'); app.set('views', join(DIST_FOLDER, '<a href="api/animations/browser" class="code-anchor">browser</a>')); // Server <a href="api/upgrade/static" class="code-anchor">static</a> files from /<a href="api/animations/browser" class="code-anchor">browser</a> app.get('*.*', express.static(join(DIST_FOLDER, '<a href="api/animations/browser" class="code-anchor">browser</a>'))); // All regular routes use the Universal engine app.get('*', (req, res) =&gt; { res.render(join(DIST_FOLDER, '<a href="api/animations/browser" class="code-anchor">browser</a>', 'index.html'), { req }); }); // Start up the Node server app.listen(PORT, () =&gt; { console.log(`Node server listening on <a href="api/common/http" class="code-anchor">http</a>://localhost:${PORT}`); });</div><aio-code><pre class="prettyprint lang-typescript">      <button class="material-icons copy-button no-print ng-star-inserted" title="Copy code snippet" aria-label="">
        <span aria-hidden="true">content_copy</span>
      </button>
      <code class="animated fadeIn"><span class="com">// These are important and needed before anything else</span><span class="pln">
</span><span class="kwd">import</span><span class="pln"> </span><span class="str">'zone.js/dist/zone-node'</span><span class="pun">;</span><span class="pln">
</span><span class="kwd">import</span><span class="pln"> </span><span class="str">'reflect-metadata'</span><span class="pun">;</span><span class="pln">

</span><span class="kwd">import</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><a href="api/platform-server/renderModuleFactory" class="code-anchor"><span class="pln">renderModuleFactory</span></a><span class="pln"> </span><span class="pun">}</span><span class="pln"> from </span><span class="str">'@angular/platform-server'</span><span class="pun">;</span><span class="pln">
</span><span class="kwd">import</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><a href="api/core/enableProdMode" class="code-anchor"><span class="pln">enableProdMode</span></a><span class="pln"> </span><span class="pun">}</span><span class="pln"> from </span><span class="str">'@angular/core'</span><span class="pun">;</span><span class="pln">
</span><span class="kwd">import</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> provideModuleMap </span><span class="pun">}</span><span class="pln"> from </span><span class="str">'@nguniversal/module-map-ngfactory-loader'</span><span class="pun">;</span><span class="pln">

</span><span class="kwd">import</span><span class="pln"> </span><span class="pun">*</span><span class="pln"> as express from </span><span class="str">'express'</span><span class="pun">;</span><span class="pln">
</span><span class="kwd">import</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> join </span><span class="pun">}</span><span class="pln"> from </span><span class="str">'path'</span><span class="pun">;</span><span class="pln">
</span><span class="kwd">import</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> readFileSync </span><span class="pun">}</span><span class="pln"> from </span><span class="str">'fs'</span><span class="pun">;</span><span class="pln">

</span><span class="com">// Faster server renders w/ Prod mode (dev mode never needed)</span><span class="pln">
</span><a href="api/core/enableProdMode" class="code-anchor"><span class="pln">enableProdMode</span></a><span class="pun">();</span><span class="pln">

</span><span class="com">// Express server</span><span class="pln">
</span><span class="kwd">const</span><span class="pln"> app </span><span class="pun">=</span><span class="pln"> express</span><span class="pun">();</span><span class="pln">

</span><span class="kwd">const</span><span class="pln"> PORT </span><span class="pun">=</span><span class="pln"> process</span><span class="pun">.</span><span class="pln">env</span><span class="pun">.</span><span class="pln">PORT </span><span class="pun">||</span><span class="pln"> </span><span class="lit">4000</span><span class="pun">;</span><span class="pln">
</span><span class="kwd">const</span><span class="pln"> DIST_FOLDER </span><span class="pun">=</span><span class="pln"> join</span><span class="pun">(</span><span class="pln">process</span><span class="pun">.</span><span class="pln">cwd</span><span class="pun">(),</span><span class="pln"> </span><span class="str">'dist'</span><span class="pun">);</span><span class="pln">

</span><span class="com">// Our index.html we'll use as our </span><a href="api/core/Component#template" class="code-anchor"><span class="com">template</span></a><span class="pln">
</span><span class="kwd">const</span><span class="pln"> </span><a href="api/core/Component#template" class="code-anchor"><span class="pln">template</span></a><span class="pln"> </span><span class="pun">=</span><span class="pln"> readFileSync</span><span class="pun">(</span><span class="pln">join</span><span class="pun">(</span><span class="pln">DIST_FOLDER</span><span class="pun">,</span><span class="pln"> </span><span class="str">'</span><a href="api/animations/browser" class="code-anchor"><span class="str">browser</span></a><span class="str">'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'index.html'</span><span class="pun">)).</span><span class="pln">toString</span><span class="pun">();</span><span class="pln">

</span><span class="kwd">const</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><span class="typ">AppServerModuleNgFactory</span><span class="pun">,</span><span class="pln"> LAZY_MODULE_MAP </span><span class="pun">}</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> require</span><span class="pun">(</span><span class="str">'./server/main'</span><span class="pun">);</span><span class="pln">


app</span><span class="pun">.</span><span class="pln">engine</span><span class="pun">(</span><span class="str">'html'</span><span class="pun">,</span><span class="pln"> </span><span class="pun">(</span><span class="pln">_</span><span class="pun">,</span><span class="pln"> options</span><span class="pun">,</span><span class="pln"> callback</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><a href="api/platform-server/renderModuleFactory" class="code-anchor"><span class="pln">renderModuleFactory</span></a><span class="pun">(</span><span class="typ">AppServerModuleNgFactory</span><span class="pun">,</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="com">// Our index.html</span><span class="pln">
    </span><a href="api/platform-server/PlatformConfig#document" class="code-anchor"><span class="pln">document</span></a><span class="pun">:</span><span class="pln"> </span><a href="api/core/Component#template" class="code-anchor"><span class="pln">template</span></a><span class="pun">,</span><span class="pln">
    url</span><span class="pun">:</span><span class="pln"> options</span><span class="pun">.</span><span class="pln">req</span><span class="pun">.</span><span class="pln">url</span><span class="pun">,</span><span class="pln">
    </span><span class="com">// DI so that we can get lazy-loading to work differently (since we need it to just instantly render it)</span><span class="pln">
    extraProviders</span><span class="pun">:</span><span class="pln"> </span><span class="pun">[</span><span class="pln">
      provideModuleMap</span><span class="pun">(</span><span class="pln">LAZY_MODULE_MAP</span><span class="pun">)</span><span class="pln">
    </span><span class="pun">]</span><span class="pln">
  </span><span class="pun">}).</span><span class="pln">then</span><span class="pun">(</span><span class="pln">html </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    callback</span><span class="pun">(</span><span class="kwd">null</span><span class="pun">,</span><span class="pln"> html</span><span class="pun">);</span><span class="pln">
  </span><span class="pun">});</span><span class="pln">
</span><span class="pun">});</span><span class="pln">

app</span><span class="pun">.</span><span class="kwd">set</span><span class="pun">(</span><span class="str">'view engine'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'html'</span><span class="pun">);</span><span class="pln">
app</span><span class="pun">.</span><span class="kwd">set</span><span class="pun">(</span><span class="str">'views'</span><span class="pun">,</span><span class="pln"> join</span><span class="pun">(</span><span class="pln">DIST_FOLDER</span><span class="pun">,</span><span class="pln"> </span><span class="str">'</span><a href="api/animations/browser" class="code-anchor"><span class="str">browser</span></a><span class="str">'</span><span class="pun">));</span><span class="pln">

</span><span class="com">// Server </span><a href="api/upgrade/static" class="code-anchor"><span class="com">static</span></a><span class="com"> files from /</span><a href="api/animations/browser" class="code-anchor"><span class="com">browser</span></a><span class="pln">
app</span><span class="pun">.</span><span class="kwd">get</span><span class="pun">(</span><span class="str">'*.*'</span><span class="pun">,</span><span class="pln"> express</span><span class="pun">.</span><span class="kwd">static</span><span class="pun">(</span><span class="pln">join</span><span class="pun">(</span><span class="pln">DIST_FOLDER</span><span class="pun">,</span><span class="pln"> </span><span class="str">'</span><a href="api/animations/browser" class="code-anchor"><span class="str">browser</span></a><span class="str">'</span><span class="pun">)));</span><span class="pln">

</span><span class="com">// All regular routes use the Universal engine</span><span class="pln">
app</span><span class="pun">.</span><span class="kwd">get</span><span class="pun">(</span><span class="str">'*'</span><span class="pun">,</span><span class="pln"> </span><span class="pun">(</span><span class="pln">req</span><span class="pun">,</span><span class="pln"> res</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  res</span><span class="pun">.</span><span class="pln">render</span><span class="pun">(</span><span class="pln">join</span><span class="pun">(</span><span class="pln">DIST_FOLDER</span><span class="pun">,</span><span class="pln"> </span><span class="str">'</span><a href="api/animations/browser" class="code-anchor"><span class="str">browser</span></a><span class="str">'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'index.html'</span><span class="pun">),</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> req </span><span class="pun">});</span><span class="pln">
</span><span class="pun">});</span><span class="pln">

</span><span class="com">// Start up the Node server</span><span class="pln">
app</span><span class="pun">.</span><span class="pln">listen</span><span class="pun">(</span><span class="pln">PORT</span><span class="pun">,</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(`</span><span class="typ">Node</span><span class="pln"> server listening on </span><a href="api/common/http" class="code-anchor"><span class="pln">http</span></a><span class="pun">:</span><span class="com">//localhost:${PORT}`);</span><span class="pln">
</span><span class="pun">});</span></code>
    </pre></aio-code></code-example><h2 id="step-5-pack-and-run-the-app-on-the-server" translation-result="on">步骤五：打包并在服务器上运行此应用<a title="Link to this heading" class="header-link" aria-hidden="true" href="guide/universal#step-5-pack-and-run-the-app-on-the-server"><i class="material-icons">link</i></a></h2><h2 translation-origin="off" id="step-5-pack-and-run-the-app-on-the-server">Step 5: Pack and run the app on the server<a title="Link to this heading" class="header-link" aria-hidden="true" href="guide/universal#step-5-pack-and-run-the-app-on-the-server"><i class="material-icons">link</i></a></h2><p translation-result="on">设置 webpack 配置，以处理 Node Express 的 <code>server.ts</code> 文件，并启动应用服务器。</p><p translation-origin="off">Set up a webpack configuration to handle the Node Express <code>server.ts</code> file and serve your application.</p><p translation-result="on">在应用的根目录下，创建一个 Webpack 配置文件 <code>webpack.server.config.js</code>，它会把 <code>server.ts</code> 及其依赖编译到 <code>dist/server.js</code> 中。</p><p translation-origin="off">In your app root directory, create a webpack configuration file (<code>webpack.server.config.js</code>) that compiles the <code>server.ts</code> file and its dependencies into <code>dist/server.js</code>.</p><code-example format="." language="typescript" linenums="false" ng-version="7.0.0"><div style="display:none">const path = require('path'); const webpack = require('webpack'); module.exports = { entry: { server: './server.ts' }, <a href="api/router/Route#resolve" class="code-anchor">resolve</a>: { extensions: ['.js', '.ts'] }, <a href="api/router/RouterLinkWithHref#target" class="code-anchor">target</a>: 'node', // this makes sure we include node_modules and other 3rd party libraries externals: [/(node_modules|main\..*\.js)/], output: { path: path.join(__dirname, 'dist'), filename: '[name].js' }, module: { rules: [ { test: /\.ts$/, loader: 'ts-loader' } ] }, plugins: [ // Temporary Fix for issue: https://github.com/angular/angular/issues/11580 // for "WARNING Critical dependency: the request of <a href="api/router/RouterLinkWithHref" class="code-anchor">a</a> dependency is an expression" new webpack.ContextReplacementPlugin( /(.+)?angular(\\|\/)core(.+)?/, path.join(__dirname, 'src'), // <a href="api/core/ComponentRef#location" class="code-anchor">location</a> of your src {} // <a href="api/router/RouterLinkWithHref" class="code-anchor">a</a> map of your routes ), new webpack.ContextReplacementPlugin( /(.+)?express(\\|\/)(.+)?/, path.join(__dirname, 'src'), {} ) ] }</div><aio-code><pre class="prettyprint lang-typescript">      <button class="material-icons copy-button no-print ng-star-inserted" title="Copy code snippet" aria-label="">
        <span aria-hidden="true">content_copy</span>
      </button>
      <code class="animated fadeIn"><span class="kwd">const</span><span class="pln"> path </span><span class="pun">=</span><span class="pln"> require</span><span class="pun">(</span><span class="str">'path'</span><span class="pun">);</span><span class="pln">
</span><span class="kwd">const</span><span class="pln"> webpack </span><span class="pun">=</span><span class="pln"> require</span><span class="pun">(</span><span class="str">'webpack'</span><span class="pun">);</span><span class="pln">

module</span><span class="pun">.</span><span class="pln">exports </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  entry</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">  server</span><span class="pun">:</span><span class="pln"> </span><span class="str">'./server.ts'</span><span class="pln"> </span><span class="pun">},</span><span class="pln">
  </span><a href="api/router/Route#resolve" class="code-anchor"><span class="pln">resolve</span></a><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> extensions</span><span class="pun">:</span><span class="pln"> </span><span class="pun">[</span><span class="str">'.js'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'.ts'</span><span class="pun">]</span><span class="pln"> </span><span class="pun">},</span><span class="pln">
  </span><a href="api/router/RouterLinkWithHref#target" class="code-anchor"><span class="pln">target</span></a><span class="pun">:</span><span class="pln"> </span><span class="str">'node'</span><span class="pun">,</span><span class="pln">
  </span><span class="com">// this makes sure we include node_modules and other 3rd party libraries</span><span class="pln">
  externals</span><span class="pun">:</span><span class="pln"> </span><span class="pun">[</span><span class="str">/(node_modules|main\..*\.js)/</span><span class="pun">],</span><span class="pln">
  output</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    path</span><span class="pun">:</span><span class="pln"> path</span><span class="pun">.</span><span class="pln">join</span><span class="pun">(</span><span class="pln">__dirname</span><span class="pun">,</span><span class="pln"> </span><span class="str">'dist'</span><span class="pun">),</span><span class="pln">
    filename</span><span class="pun">:</span><span class="pln"> </span><span class="str">'[name].js'</span><span class="pln">
  </span><span class="pun">},</span><span class="pln">
  module</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    rules</span><span class="pun">:</span><span class="pln"> </span><span class="pun">[</span><span class="pln">
      </span><span class="pun">{</span><span class="pln"> test</span><span class="pun">:</span><span class="pln"> </span><span class="str">/\.ts$/</span><span class="pun">,</span><span class="pln"> loader</span><span class="pun">:</span><span class="pln"> </span><span class="str">'ts-loader'</span><span class="pln"> </span><span class="pun">}</span><span class="pln">
    </span><span class="pun">]</span><span class="pln">
  </span><span class="pun">},</span><span class="pln">
  plugins</span><span class="pun">:</span><span class="pln"> </span><span class="pun">[</span><span class="pln">
    </span><span class="com">// Temporary Fix for issue: https://github.com/angular/angular/issues/11580</span><span class="pln">
    </span><span class="com">// for "WARNING Critical dependency: the request of </span><a href="api/router/RouterLinkWithHref" class="code-anchor"><span class="com">a</span></a><span class="com"> dependency is an expression"</span><span class="pln">
    </span><span class="kwd">new</span><span class="pln"> webpack</span><span class="pun">.</span><span class="typ">ContextReplacementPlugin</span><span class="pun">(</span><span class="pln">
      </span><span class="str">/(.+)?angular(\\|\/)core(.+)?/</span><span class="pun">,</span><span class="pln">
      path</span><span class="pun">.</span><span class="pln">join</span><span class="pun">(</span><span class="pln">__dirname</span><span class="pun">,</span><span class="pln"> </span><span class="str">'src'</span><span class="pun">),</span><span class="pln"> </span><span class="com">// </span><a href="api/core/ComponentRef#location" class="code-anchor"><span class="com">location</span></a><span class="com"> of your src</span><span class="pln">
      </span><span class="pun">{}</span><span class="pln"> </span><span class="com">// </span><a href="api/router/RouterLinkWithHref" class="code-anchor"><span class="com">a</span></a><span class="com"> map of your routes</span><span class="pln">
    </span><span class="pun">),</span><span class="pln">
    </span><span class="kwd">new</span><span class="pln"> webpack</span><span class="pun">.</span><span class="typ">ContextReplacementPlugin</span><span class="pun">(</span><span class="pln">
      </span><span class="str">/(.+)?express(\\|\/)(.+)?/</span><span class="pun">,</span><span class="pln">
      path</span><span class="pun">.</span><span class="pln">join</span><span class="pun">(</span><span class="pln">__dirname</span><span class="pun">,</span><span class="pln"> </span><span class="str">'src'</span><span class="pun">),</span><span class="pln">
      </span><span class="pun">{}</span><span class="pln">
    </span><span class="pun">)</span><span class="pln">
  </span><span class="pun">]</span><span class="pln">
</span><span class="pun">}</span></code>
    </pre></aio-code></code-example><p translation-result="on">项目的 <code>dist/</code> 目录现在同时包含 browser 目录和 server 目录。</p><p translation-origin="off">The project's <code>dist/</code> folder now contains both browser and server folders.</p><code-example format="." language="none" linenums="false" ng-version="7.0.0"><div style="display:none">dist/ <a href="api/animations/browser" class="code-anchor">browser</a>/ server/</div><aio-code><pre class="prettyprint lang-none">      <button class="material-icons copy-button no-print ng-star-inserted" title="Copy code snippet" aria-label="">
        <span aria-hidden="true">content_copy</span>
      </button>
      <code class="animated fadeIn"><span class="pln">dist</span><span class="pun">/</span><span class="pln">
   </span><a href="api/animations/browser" class="code-anchor"><span class="pln">browser</span></a><span class="pun">/</span><span class="pln">
   server</span><span class="pun">/</span></code>
    </pre></aio-code></code-example><p translation-result="on">要想在服务器上运行该应用，请在命令行窗口运行下列命令：</p><p translation-origin="off">To run the app on the server, type the following in a command shell.</p><code-example format="." language="bash" linenums="false" ng-version="7.0.0"><div style="display:none">node dist/server.js</div><aio-code><pre class="prettyprint lang-bash">      <button class="material-icons copy-button no-print ng-star-inserted" title="Copy code snippet" aria-label="">
        <span aria-hidden="true">content_copy</span>
      </button>
      <code class="animated fadeIn"><span class="pln">node dist</span><span class="pun">/</span><span class="pln">server</span><span class="pun">.</span><span class="pln">js</span></code>
    </pre></aio-code></code-example><h3 id="creating-scripts" translation-result="on">创建一些脚本<a title="Link to this heading" class="header-link" aria-hidden="true" href="guide/universal#creating-scripts"><i class="material-icons">link</i></a></h3><h3 translation-origin="off" id="creating-scripts">Creating scripts<a title="Link to this heading" class="header-link" aria-hidden="true" href="guide/universal#creating-scripts"><i class="material-icons">link</i></a></h3><p translation-result="on">现在，来创建一些便利脚本，以便将来帮我们完成这些琐事。 你可以在 <code>package.json</code> 的 <code>"scripts"</code> 区添加这些脚本。</p><p translation-origin="off">Now let's create a few handy scripts to help us do all of this in the future. You can add these in the <code>"scripts"</code> section of the <code>package.json</code>.</p><code-example format="." language="none" linenums="false" ng-version="7.0.0"><div style="display:none">"scripts": { "build:ssr": "npm run build:client-and-server-bundles &amp;&amp; npm run webpack:server", "serve:ssr": "node dist/server.js", "build:client-and-server-bundles": "ng build --prod &amp;&amp; ng run my-project:server:production", "webpack:server": "webpack --config webpack.server.config.js --progress --colors", ... }</div><aio-code><pre class="prettyprint lang-none">      <button class="material-icons copy-button no-print ng-star-inserted" title="Copy code snippet" aria-label="">
        <span aria-hidden="true">content_copy</span>
      </button>
      <code class="animated fadeIn"><span class="str">"scripts"</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="str">"build:ssr"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"npm run build:client-and-server-bundles &amp;&amp; npm run webpack:server"</span><span class="pun">,</span><span class="pln">
  </span><span class="str">"serve:ssr"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"node dist/server.js"</span><span class="pun">,</span><span class="pln">
  </span><span class="str">"build:client-and-server-bundles"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"ng build --prod &amp;&amp; ng run my-project:server:production"</span><span class="pun">,</span><span class="pln">
  </span><span class="str">"webpack:server"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"webpack --config webpack.server.config.js --progress --colors"</span><span class="pun">,</span><span class="pln">
  </span><span class="pun">...</span><span class="pln">
</span><span class="pun">}</span></code>
    </pre></aio-code></code-example><p translation-result="on">要想在本地系统上使用 Universal 运行应用的生产版本，请使用如下命令：</p><p translation-origin="off">To run a production build of your app with Universal on your local system, use the following command.</p><code-example format="." language="bash" linenums="false" ng-version="7.0.0"><div style="display:none">npm run build:ssr &amp;&amp; npm run serve:ssr</div><aio-code><pre class="prettyprint lang-bash">      <button class="material-icons copy-button no-print ng-star-inserted" title="Copy code snippet" aria-label="">
        <span aria-hidden="true">content_copy</span>
      </button>
      <code class="animated fadeIn"><span class="pln">npm run build</span><span class="pun">:</span><span class="pln">ssr </span><span class="pun">&amp;&amp;</span><span class="pln"> npm run serve</span><span class="pun">:</span><span class="pln">ssr</span></code>
    </pre></aio-code></code-example><h3 id="working-around-the-browser-apis" translation-result="on">使用浏览器 API<a title="Link to this heading" class="header-link" aria-hidden="true" href="guide/universal#working-around-the-browser-apis"><i class="material-icons">link</i></a></h3><h3 translation-origin="off" id="working-around-the-browser-apis">Working around the browser APIs<a title="Link to this heading" class="header-link" aria-hidden="true" href="guide/universal#working-around-the-browser-apis"><i class="material-icons">link</i></a></h3><p translation-result="on">由于 Universal 的 <code>platform-server</code> 应用并没有运行在浏览器中，因此你不得不在该服务器中缺少某些浏览器 API 和能力的情况下工作。</p><p translation-origin="off">Because a Universal <code>platform-server</code> app doesn't execute in the browser, you may have to work around some of the browser APIs and capabilities that are missing on the server.</p><p translation-result="on">比如，你的服务端渲染页面不能引用浏览器独有的原生对象，比如 <code>window</code>、<code><a href="api/platform-server/PlatformConfig#document" class="code-anchor">document</a></code>、<code>navigator</code> 或 <code><a href="api/core/ComponentRef#location" class="code-anchor">location</a></code>。 如果你在服务端渲染的页面中不需要它们，就可以使用条件逻辑跳过它们。 另一种方式是查找一个可注入的 Angular 对所需对象的抽象服务，比如 <code><a href="api/common/Location" class="code-anchor">Location</a></code> 或 <code>Document</code>，它可能作为你调用的指定 API 的等价替身。 如果 Angular 没有提供它，你也可以写一个自己的抽象层，当在浏览器中运行时，就把它委托给浏览器 API，当它在服务器中运行时，就提供一个符合要求的代用实现。</p><p translation-origin="off">For example, your server-side page can't reference browser-only native objects such as <code>window</code>, <code><a href="api/platform-server/PlatformConfig#document" class="code-anchor">document</a></code>, <code>navigator</code>, or <code><a href="api/core/ComponentRef#location" class="code-anchor">location</a></code>. If you don't need these on the server-rendered page, you can side-step them with conditional logic. Alternatively, you can find an injectable Angular abstraction over the object you need such as <code><a href="api/common/Location" class="code-anchor">Location</a></code> or <code>Document</code>; it may substitute adequately for the specific API that you're calling. If Angular doesn't provide it, you can write your own abstraction that delegates to the browser API while in the browser and to a satisfactory alternative implementation while on the server.</p><p translation-result="on">同样，由于没有鼠标或键盘事件，因此 Universal 应用也不能依赖于用户点击某个按钮来显示每个组件。 Universal 应用必须仅仅根据客户端过来的请求决定要渲染的内容。 把该应用做成<a href="guide/router">可路由的</a>，就是一种好方案。</p><p translation-origin="off">Similarly, without mouse or keyboard events, a server-side app can't rely on a user clicking a button to show a component. The app must determine what to render based solely on the incoming client request. This is a good argument for making the app <a href="guide/router">routable</a>.</p><p translation-result="on">由于服务端渲染页面的用户只能点击链接，所以你应该尽快让它切换到真正的客户端应用，以提供正常的交互体验。</p><p translation-origin="off">Because the user of a server-rendered page can't do much more than click links, you should swap in the real client app as quickly as possible for a proper interactive experience.</p><a id="the-example"></a><h2 id="universal-tutorial" translation-result="on">例子<a title="Link to this heading" class="header-link" aria-hidden="true" href="guide/universal#universal-tutorial"><i class="material-icons">link</i></a></h2><h2 translation-origin="off" id="universal-tutorial">Universal tutorial<a title="Link to this heading" class="header-link" aria-hidden="true" href="guide/universal#universal-tutorial"><i class="material-icons">link</i></a></h2><p translation-result="on"><a href="tutorial">《英雄指南》教程</a>是本章所讲的 Universal 范例的基础。</p><p translation-origin="off">The <a href="tutorial">Tour of Heroes tutorial</a> is the foundation for this walkthrough.</p><p translation-result="on">除了下面讲的少量修改之外，应用中的核心文件几乎不用动。 你只需要添加一些额外的文件来支持使用 Universal 进行构建和提供服务。</p><p translation-origin="off">The core application files are mostly untouched, with a few exceptions described below. You'll add more files to support building and serving with Universal.</p><p translation-result="on">在这个例子中，Angular CLI 会使用 <a href="guide/aot-compiler">AOT (预先) 编译器</a>对该应用的 Universal 版本进行编译和打包。 Node.js® 的 Express Web 服务器会把客户端请求转换成由 Universal 渲染出的页面。</p><p translation-origin="off">In this example, the Angular CLI compiles and bundles the Universal version of the app with the <a href="guide/aot-compiler">Ahead-of-Time (AoT) compiler</a>. A Node Express web server turns client requests into the HTML pages rendered by Universal.</p><p translation-result="on">要想创建服务端渲染模块 <code>app.server.module.ts</code>，请运行下列 CLI 命令。</p><p translation-origin="off">To create server-side app module, <code>app.server.module.ts</code>, run the following CLI command.</p><code-example format="." language="bash" ng-version="7.0.0"><div style="display:none">ng add @nguniversal/express-engine --clientProject angular.io-example</div><aio-code><pre class="prettyprint lang-bash">      <button class="material-icons copy-button no-print ng-star-inserted" title="Copy code snippet" aria-label="">
        <span aria-hidden="true">content_copy</span>
      </button>
      <code class="animated fadeIn"><span class="pln">ng add </span><span class="lit">@nguniversal</span><span class="pun">/</span><span class="pln">express</span><span class="pun">-</span><span class="pln">engine </span><span class="pun">--</span><span class="pln">clientProject angular</span><span class="pun">.</span><span class="pln">io</span><span class="pun">-</span><span class="pln">example</span></code>
    </pre></aio-code></code-example><p translation-result="on">该命令会创建如下的目录结构。</p><p translation-origin="off">The command creates the following folder structure.</p><code-example format="." language="none" linenums="false" ng-version="7.0.0"><div style="display:none">src/ index.html<t translation-result="on">应用的宿主页</t><t translation-origin="off"><i>app web page</i></t>main.ts<t translation-result="on">客户端应用的引导程序</t><t translation-origin="off"><i>bootstrapper for client app</i></t>main.server.ts<t translation-result="on">* 服务端应用的引导程序</t><t translation-origin="off"><i>* bootstrapper for server app</i></t>tsconfig.app.json<t translation-result="on">TypeScript 的客户端配置</t><t translation-origin="off"><i>TypeScript client configuration</i></t>tsconfig.server.json<t translation-result="on">* TypeScript 的服务端配置</t><t translation-origin="off"><i>* TypeScript server configuration</i></t>tsconfig.spec.json<t translation-result="on">TypeScript 的测试配置</t><t translation-origin="off"><i>TypeScript spec configuration</i></t>style.css<t translation-result="on">应用的样式表</t><t translation-origin="off"><i>styles for the app</i></t>app/ ...<t translation-result="on">应用代码</t><t translation-origin="off"><i>application code</i></t>app.server.module.ts<t translation-result="on">* 服务端的应用模块</t><t translation-origin="off"><i>* server-side application module</i></t>server.ts<t translation-result="on">* Express 的服务程序</t><t translation-origin="off"><i>* express web server</i></t>tsconfig.json<t translation-result="on">TypeScript 的客户端配置</t><t translation-origin="off"><i>TypeScript client configuration</i></t>package.json<t translation-result="on">npm 配置</t><t translation-origin="off"><i>npm configuration</i></t>webpack.server.config.js<t translation-result="on">* Webpack 的服务端配置</t><t translation-origin="off"><i>* webpack server configuration</i></t></div><aio-code><pre class="prettyprint lang-none">      <button class="material-icons copy-button no-print ng-star-inserted" title="Copy code snippet" aria-label="">
        <span aria-hidden="true">content_copy</span>
      </button>
      <code class="animated fadeIn"><span class="pln">src</span><span class="pun">/</span><span class="pln">
  index</span><span class="pun">.</span><span class="pln">html                 </span><t translation-result="on"><span class="pun">应用的宿主页</span></t><t translation-origin="off"><i><span class="pln">app web page</span></i></t><span class="pln">
  main</span><span class="pun">.</span><span class="pln">ts                    </span><t translation-result="on"><span class="pun">客户端应用的引导程序</span></t><t translation-origin="off"><i><span class="pln">bootstrapper </span><span class="kwd">for</span><span class="pln"> client app</span></i></t><span class="pln">
  main</span><span class="pun">.</span><span class="pln">server</span><span class="pun">.</span><span class="pln">ts             </span><t translation-result="on"><span class="pun">*</span><span class="pln"> </span><span class="pun">服务端应用的引导程序</span></t><t translation-origin="off"><i><span class="pun">*</span><span class="pln"> bootstrapper </span><span class="kwd">for</span><span class="pln"> server app</span></i></t><span class="pln">
  tsconfig</span><span class="pun">.</span><span class="pln">app</span><span class="pun">.</span><span class="pln">json          </span><t translation-result="on"><span class="typ">TypeScript</span><span class="pln"> </span><span class="pun">的客户端配置</span></t><t translation-origin="off"><i><span class="typ">TypeScript</span><span class="pln"> client configuration</span></i></t><span class="pln">
  tsconfig</span><span class="pun">.</span><span class="pln">server</span><span class="pun">.</span><span class="pln">json       </span><t translation-result="on"><span class="pun">*</span><span class="pln"> </span><span class="typ">TypeScript</span><span class="pln"> </span><span class="pun">的服务端配置</span></t><t translation-origin="off"><i><span class="pun">*</span><span class="pln"> </span><span class="typ">TypeScript</span><span class="pln"> server configuration</span></i></t><span class="pln">
  tsconfig</span><span class="pun">.</span><span class="pln">spec</span><span class="pun">.</span><span class="pln">json         </span><t translation-result="on"><span class="typ">TypeScript</span><span class="pln"> </span><span class="pun">的测试配置</span></t><t translation-origin="off"><i><span class="typ">TypeScript</span><span class="pln"> spec configuration</span></i></t><span class="pln">
  style</span><span class="pun">.</span><span class="pln">css                  </span><t translation-result="on"><span class="pun">应用的样式表</span></t><t translation-origin="off"><i><span class="pln">styles </span><span class="kwd">for</span><span class="pln"> the app</span></i></t><span class="pln">
  app</span><span class="pun">/</span><span class="pln"> </span><span class="pun">...</span><span class="pln">                   </span><t translation-result="on"><span class="pun">应用代码</span></t><t translation-origin="off"><i><span class="pln">application code</span></i></t><span class="pln">
    app</span><span class="pun">.</span><span class="pln">server</span><span class="pun">.</span><span class="kwd">module</span><span class="pun">.</span><span class="pln">ts     </span><t translation-result="on"><span class="pun">*</span><span class="pln"> </span><span class="pun">服务端的应用模块</span></t><t translation-origin="off"><i><span class="pun">*</span><span class="pln"> server</span><span class="pun">-</span><span class="pln">side application </span><span class="kwd">module</span></i></t><span class="pln">
server</span><span class="pun">.</span><span class="pln">ts                    </span><t translation-result="on"><span class="pun">*</span><span class="pln"> </span><span class="typ">Express</span><span class="pln"> </span><span class="pun">的服务程序</span></t><t translation-origin="off"><i><span class="pun">*</span><span class="pln"> express web server</span></i></t><span class="pln">
tsconfig</span><span class="pun">.</span><span class="pln">json                </span><t translation-result="on"><span class="typ">TypeScript</span><span class="pln"> </span><span class="pun">的客户端配置</span></t><t translation-origin="off"><i><span class="typ">TypeScript</span><span class="pln"> client configuration</span></i></t><span class="pln">
</span><span class="kwd">package</span><span class="pun">.</span><span class="pln">json                 </span><t translation-result="on"><span class="pln">npm </span><span class="pun">配置</span></t><t translation-origin="off"><i><span class="pln">npm configuration</span></i></t><span class="pln">
webpack</span><span class="pun">.</span><span class="pln">server</span><span class="pun">.</span><span class="pln">config</span><span class="pun">.</span><span class="pln">js     </span><t translation-result="on"><span class="pun">*</span><span class="pln"> </span><span class="typ">Webpack</span><span class="pln"> </span><span class="pun">的服务端配置</span></t><t translation-origin="off"><i><span class="pun">*</span><span class="pln"> webpack server configuration</span></i></t></code>
    </pre></aio-code></code-example><p translation-result="on">那些标有 <code>*</code> 的文件都是新的，而不是来自原来的范例应用。 本文稍后的部分会涉及它们。</p><p translation-origin="off">The files marked with <code>*</code> are new and not in the original tutorial sample. This guide covers them in the sections below.</p><a id="http-urls"></a><h3 id="using-absolute-urls-for-server-requests" translation-result="on">在 HTTP 中使用绝对地址<a title="Link to this heading" class="header-link" aria-hidden="true" href="guide/universal#using-absolute-urls-for-server-requests"><i class="material-icons">link</i></a></h3><h3 translation-origin="off" id="using-absolute-urls-for-server-requests">Using absolute URLs for server requests<a title="Link to this heading" class="header-link" aria-hidden="true" href="guide/universal#using-absolute-urls-for-server-requests"><i class="material-icons">link</i></a></h3><p translation-result="on">教程中的 <code>HeroService</code> 和 <code>HeroSearchService</code> 都委托了 Angular 的 <code><a href="api/common/http/HttpClient" class="code-anchor">HttpClient</a></code> 模块来获取应用数据。 那些服务都把请求发送到了<em>相对</em> URL，比如 <code>api/heroes</code>。</p><p translation-origin="off">The tutorial's <code>HeroService</code> and <code>HeroSearchService</code> delegate to the Angular <code><a href="api/common/http/HttpClient" class="code-anchor">HttpClient</a></code> module to fetch application data. These services send requests to <em>relative</em> URLs such as <code>api/heroes</code>.</p><p translation-result="on">在 Universal 应用中，HTTP 的 URL 必须是<em>绝对地址</em>（比如 <code>https://my-server.com/api/heroes</code>）， 只有这样，Universal 的 Web 服务器才能处理那些请求。 这意味着当运行在服务端时，你要修改你的服务，来使用绝对 URL发起请求，而在浏览器中，则使用相对 URL。</p><p translation-origin="off">In a Universal app, HTTP URLs must be <em>absolute</em>(for example, <code>https://my-server.com/api/heroes</code>) even when the Universal web server is capable of handling relative requests. This means you need to change your services to make requests with absolute URLs when running on the server and with relative URLs when running in the browser.</p><p translation-result="on">解决方案之一是通过 Angular 的 <a href="api/common/APP_BASE_HREF"><code>APP_BASE_HREF</code> 令牌</a>来提供服务器的源地址（origin），把它注入到服务中，并把这个源地址添加到所请求的 URL 之前。</p><p translation-origin="off">One solution is to provide the server's runtime origin under Angular's <a href="api/common/APP_BASE_HREF"><code>APP_BASE_HREF</code></a>token, inject it into the service, and prepend the origin to the request URL.</p><p translation-result="on">先为 <code>HeroService</code> 的构造函数添加第二个参数 <code>origin</code>，它是可选的，并通过 <code><a href="api/common/APP_BASE_HREF" class="code-anchor">APP_BASE_HREF</a></code> 令牌进行注入。</p><p translation-origin="off">Start by changing the <code>HeroService</code> constructor to take a second <code>origin</code> parameter that is optionally injected via the <code><a href="api/common/APP_BASE_HREF" class="code-anchor">APP_BASE_HREF</a></code> token.</p><code-example path="universal/src/app/hero.service.ts" region="ctor" header="src/app/hero.service.ts (constructor with optional origin)" ng-version="7.0.0"><div style="display:none">constructor( private <a href="api/common/http" class="code-anchor">http</a>: <a href="api/common/http/HttpClient" class="code-anchor">HttpClient</a>, private messageService: MessageService, @<a href="api/core/Optional" class="code-anchor">Optional</a>() @<a href="api/core/Inject" class="code-anchor">Inject</a>(<a href="api/common/APP_BASE_HREF" class="code-anchor">APP_BASE_HREF</a>) origin: string) { this.heroesUrl = `${origin}${this.heroesUrl}`; }</div><header class="ng-star-inserted">src/app/hero.service.ts (constructor with optional origin)</header><aio-code class="headed-code"><pre class="prettyprint lang-">      <button class="material-icons copy-button no-print ng-star-inserted" title="Copy code snippet" aria-label="Copy code snippet from src/app/hero.service.ts (constructor with optional origin)">
        <span aria-hidden="true">content_copy</span>
      </button>
      <code class="animated fadeIn"><span class="kwd">constructor</span><span class="pun">(</span><span class="pln">
  </span><span class="kwd">private</span><span class="pln"> </span><a href="api/common/http" class="code-anchor"><span class="pln">http</span></a><span class="pun">:</span><span class="pln"> </span><a href="api/common/http/HttpClient" class="code-anchor"><span class="typ">HttpClient</span></a><span class="pun">,</span><span class="pln">
  </span><span class="kwd">private</span><span class="pln"> messageService</span><span class="pun">:</span><span class="pln"> </span><span class="typ">MessageService</span><span class="pun">,</span><span class="pln">
  </span><span class="lit">@</span><a href="api/core/Optional" class="code-anchor"><span class="lit">Optional</span></a><span class="pun">()</span><span class="pln"> </span><span class="lit">@</span><a href="api/core/Inject" class="code-anchor"><span class="lit">Inject</span></a><span class="pun">(</span><a href="api/common/APP_BASE_HREF" class="code-anchor"><span class="pln">APP_BASE_HREF</span></a><span class="pun">)</span><span class="pln"> origin</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">string</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">heroesUrl </span><span class="pun">=</span><span class="pln"> </span><span class="str">`${origin}${this.heroesUrl}`</span><span class="pun">;</span><span class="pln">
  </span><span class="pun">}</span></code>
    </pre></aio-code></code-example><p translation-result="on">这个构造函数使用了 <code>@<a href="api/core/Optional" class="code-anchor">Optional</a>()</code> 指令来为 <code>heroesUrl</code> 添加源（如果有的话）。</p><p translation-origin="off">The constructor uses the <code>@<a href="api/core/Optional" class="code-anchor">Optional</a>()</code> directive to prepend the origin to <code>heroesUrl</code> <em>if it exists</em>.</p><p translation-result="on">在浏览器版本中，你不用提供 <code><a href="api/common/APP_BASE_HREF" class="code-anchor">APP_BASE_HREF</a></code>，因此 <code>heroesUrl</code> 仍然是相对的。</p><p translation-origin="off">You don't provide <code><a href="api/common/APP_BASE_HREF" class="code-anchor">APP_BASE_HREF</a></code> in the browser version, so <code>heroesUrl</code> remains relative.</p><div class="alert is-helpful"><p translation-result="on"><strong>注意：</strong> 如果你通过 <code>index.html</code> 文件指定了 <code>&lt;base <a href="api/router/RouterLinkWithHref#href" class="code-anchor">href</a>="/"&gt;</code> 以满足路由器对基地址的要求（就像教程中示范的那样），那么就可以在浏览器中忽略 <code><a href="api/common/APP_BASE_HREF" class="code-anchor">APP_BASE_HREF</a></code> 的设置。</p><p translation-origin="off"><strong>Note:</strong> You can ignore <code><a href="api/common/APP_BASE_HREF" class="code-anchor">APP_BASE_HREF</a></code> in the browser if you've specified <code>&lt;base <a href="api/router/RouterLinkWithHref#href" class="code-anchor">href</a>="/"&gt;</code> in the <code>index.html</code> file to satisfy the router's need for a base address (as the tutorial sample does).</p></div><a id="universal-engine"></a><h3 id="universal-template-engine" translation-result="on">Universal 模板引擎<a title="Link to this heading" class="header-link" aria-hidden="true" href="guide/universal#universal-template-engine"><i class="material-icons">link</i></a></h3><h3 translation-origin="off" id="universal-template-engine">Universal template engine<a title="Link to this heading" class="header-link" aria-hidden="true" href="guide/universal#universal-template-engine"><i class="material-icons">link</i></a></h3><p translation-result="on"><code>server.ts</code> 文件中最重要的部分是 <code>ngExpressEngine()</code> 函数：</p><p translation-origin="off">The important bit in the <code>server.ts</code> file is the <code>ngExpressEngine()</code> function.</p><code-example path="universal/server.ts" header="server.ts" region="ngExpressEngine" ng-version="7.0.0"><div style="display:none">app.engine('html', ngExpressEngine({ <a href="api/core/NgModule#bootstrap" class="code-anchor">bootstrap</a>: AppServerModuleNgFactory, providers: [ provideModuleMap(LAZY_MODULE_MAP) ] }));</div><header class="ng-star-inserted">server.ts</header><aio-code class="headed-code"><pre class="prettyprint lang-">      <button class="material-icons copy-button no-print ng-star-inserted" title="Copy code snippet" aria-label="Copy code snippet from server.ts">
        <span aria-hidden="true">content_copy</span>
      </button>
      <code class="animated fadeIn"><span class="pln">app</span><span class="pun">.</span><span class="pln">engine</span><span class="pun">(</span><span class="str">'html'</span><span class="pun">,</span><span class="pln"> ngExpressEngine</span><span class="pun">({</span><span class="pln">
  </span><a href="api/core/NgModule#bootstrap" class="code-anchor"><span class="pln">bootstrap</span></a><span class="pun">:</span><span class="pln"> </span><span class="typ">AppServerModuleNgFactory</span><span class="pun">,</span><span class="pln">
  providers</span><span class="pun">:</span><span class="pln"> </span><span class="pun">[</span><span class="pln">
    provideModuleMap</span><span class="pun">(</span><span class="pln">LAZY_MODULE_MAP</span><span class="pun">)</span><span class="pln">
  </span><span class="pun">]</span><span class="pln">
</span><span class="pun">}));</span></code>
    </pre></aio-code></code-example><p translation-result="on"><code>ngExpressEngine()</code> 是对 Universal 的 <code><a href="api/platform-server/renderModuleFactory" class="code-anchor">renderModuleFactory</a>()</code> 函数的封装。它会把客户端请求转换成服务端渲染的 HTML 页面。 你还要在某个适用于你服务端技术栈的<em>模板引擎</em>中调用这个函数。</p><p translation-origin="off">The <code>ngExpressEngine()</code> function is a wrapper around Universal's <code><a href="api/platform-server/renderModuleFactory" class="code-anchor">renderModuleFactory</a>()</code> function which turns a client's requests into server-rendered HTML pages. You'll call that function within a <em>template engine</em> that's appropriate for your server stack.</p><ul><li><p translation-result="on">第一个参数是 <code>AppServerModule</code>。 它是 Universal 服务端渲染器和你的应用之间的桥梁。</p><p translation-origin="off">The first parameter is <code>AppServerModule</code>. It's the bridge between the Universal server-side renderer and your application.</p></li><li><p translation-result="on">第二个参数 <code>extraProviders</code> 是可选的。它能让你指定一些在服务端运行时特有的服务提供商。 只有当你的应用需要一些运行在服务器中才需要的信息时，才需要这么做。 这个例子中所需的信息就是正在运行的服务器的<em>源</em>地址，它通过 <code><a href="api/common/APP_BASE_HREF" class="code-anchor">APP_BASE_HREF</a></code> 令牌提供，以便应用可以 <a href="guide/universal#http-urls">计算出 HTTP URL 的绝对地址</a>。</p><p translation-origin="off">The second parameter, <code>extraProviders</code>, is optional. It lets you specify dependency providers that apply only when running on this server. You can do this when your app needs information that can only be determined by the currently running server instance. The required information in this case is the running server's <em>origin</em>, provided under the <code><a href="api/common/APP_BASE_HREF" class="code-anchor">APP_BASE_HREF</a></code> token, so that the app can <a href="guide/universal#http-urls">calculate absolute HTTP URLs</a>.</p></li></ul><p translation-result="on"><code>ngExpressEngine()</code> 函数返回了一个会解析成渲染好的页面的<em>承诺（Promise）</em>。</p><p translation-origin="off">The <code>ngExpressEngine()</code> function returns a <code>Promise</code> callback that resolves to the rendered page.</p><p translation-result="on">接下来你的引擎要决定拿这个页面做点什么。 在<em>这个引擎</em>的 <code>Promise</code> 回调函数中，把渲染好的页面返回给了 Web 服务器，然后服务器通过 HTTP 响应把它转发给了客户端。</p><p translation-origin="off">It's up to your engine to decide what to do with that page. This engine's <code>Promise</code> callback returns the rendered page to the web server, which then forwards it to the client in the HTTP response.</p><div class="alert is-helpful"><p translation-result="on"><strong>注意：</strong> 这个包装器帮助隐藏了 <code><a href="api/platform-server/renderModuleFactory" class="code-anchor">renderModuleFactory</a>()</code> 的复杂性。 在 <a href="https://github.com/angular/universal">Universal 代码库中</a>还有更多针对其它后端技术的包装器。</p><p translation-origin="off"><strong>Note:</strong> These wrappers help hide the complexity of the <code><a href="api/platform-server/renderModuleFactory" class="code-anchor">renderModuleFactory</a>()</code> function. There are more wrappers for different backend technologies at the <a href="https://github.com/angular/universal">Universal repository</a>.</p></div><h3 id="filtering-request-urls" translation-result="on">过滤请求的 URL<a title="Link to this heading" class="header-link" aria-hidden="true" href="guide/universal#filtering-request-urls"><i class="material-icons">link</i></a></h3><h3 translation-origin="off" id="filtering-request-urls">Filtering request URLs<a title="Link to this heading" class="header-link" aria-hidden="true" href="guide/universal#filtering-request-urls"><i class="material-icons">link</i></a></h3><p translation-result="on">Web 服务器必须把<em>对应用页面的请求</em>和其它类型的请求区分开。</p><p translation-origin="off">The web server must distinguish <em>app page requests</em> from other kinds of requests.</p><p translation-result="on">这可不像拦截对根路径 <code>/</code> 的请求那么简单。 浏览器可以请求应用中的任何一个路由地址，比如 <code>/dashboard</code>、<code>/heroes</code> 或 <code>/detail:12</code>。 事实上，如果应用<em>只</em>会通过服务器渲染，那么应用中点击的<em>任何一个</em>链接都会发到服务器，就像导航时的地址会发到路由器一样。</p><p translation-origin="off">It's not as simple as intercepting a request to the root address <code>/</code>. The browser could ask for one of the application routes such as <code>/dashboard</code>, <code>/heroes</code>, or <code>/detail:12</code>. In fact, if the app were only rendered by the server, <em>every</em> app link clicked would arrive at the server as a navigation URL intended for the router.</p><p translation-result="on">幸运的是，应用的路由具有一些共同特征：它们的 URL 一般不带文件扩展名。 （数据请求也可能缺少扩展名，但是它们很容易识别出来，因为它们总是以 <code>/api</code> 开头，所有的静态资源的请求都会带有一个扩展名，比如 <code>main.js</code> 或 <code>/node_modules/zone.js/dist/zone.js</code>）。</p><p translation-origin="off">Fortunately, application routes have something in common: their URLs lack file extensions. (Data requests also lack extensions but they're easy to recognize because they always begin with <code>/api</code>.) All static asset requests have a file extension (such as <code>main.js</code> or <code>/node_modules/zone.js/dist/zone.js</code>).</p><p translation-result="on">由于使用了路由，所以我们可以轻松的识别出这三种类型的请求，并分别处理它们。</p><p translation-origin="off">Because we use routing, we can easily recognize the three types of requests and handle them differently.</p><ol><li><p translation-result="on">数据请求 - 请求的 URL 用 <code>/api</code> 开头</p><p translation-origin="off">Data request - request URL that begins <code>/api</code>.</p></li><li><p translation-result="on">应用导航 - 请求的 URL 不带扩展名</p><p translation-origin="off">App navigation - request URL with no file extension.</p></li><li><p translation-result="on">静态资源 - 所有其它请求。</p><p translation-origin="off">Static asset - all other requests.</p></li></ol><p translation-result="on">Node Express 服务器是一系列中间件构成的管道，它会挨个对 URL 请求进行过滤和处理。 你可以调用 <code>app.get()</code> 来配置 Express 服务器的管道，就像下面这个数据请求一样：</p><p translation-origin="off">A Node Express server is a pipeline of middleware that filters and processes URL requests one after the other. You configure the Node Express server pipeline with calls to <code>app.get()</code> like this one for data requests.</p><code-example path="universal/server.ts" header="server.ts (data URL)" region="data-request" linenums="false" ng-version="7.0.0"><div style="display:none">// TODO: implement data requests securely app.get('/api/*', (req, res) =&gt; { res.status(404).send('data requests are not supported'); });</div><header class="ng-star-inserted">server.ts (data URL)</header><aio-code class="headed-code"><pre class="prettyprint lang-">      <button class="material-icons copy-button no-print ng-star-inserted" title="Copy code snippet" aria-label="Copy code snippet from server.ts (data URL)">
        <span aria-hidden="true">content_copy</span>
      </button>
      <code class="animated fadeIn"><span class="com">// TODO: implement data requests securely</span><span class="pln">
app</span><span class="pun">.</span><span class="kwd">get</span><span class="pun">(</span><span class="str">'/api/*'</span><span class="pun">,</span><span class="pln"> </span><span class="pun">(</span><span class="pln">req</span><span class="pun">,</span><span class="pln"> res</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  res</span><span class="pun">.</span><span class="pln">status</span><span class="pun">(</span><span class="lit">404</span><span class="pun">).</span><span class="pln">send</span><span class="pun">(</span><span class="str">'data requests are not supported'</span><span class="pun">);</span><span class="pln">
</span><span class="pun">});</span></code>
    </pre></aio-code></code-example><div class="alert is-helpful"><p translation-result="on"><strong>注意：</strong>这个范例服务器不会处理数据请求。</p><p translation-origin="off"><strong>Note:</strong> This sample server doesn't handle data requests.</p><p translation-result="on">本教程的“内存 Web API” 模块（一个演示及开发工具）拦截了所有 HTTP 调用，并且模拟了远端数据服务器的行为。 在实践中，你应该移除这个模块，并且在服务器上注册你的 Web API 中间件。</p><p translation-origin="off">The tutorial's "in-memory web API" module, a demo and development tool, intercepts all HTTP calls and simulates the behavior of a remote data server. In practice, you would remove that module and register your web API middleware on the server here.</p></div><p translation-result="on">下列代码会过滤出不带扩展名的 URL，并把它们当做导航请求进行处理。</p><p translation-origin="off">The following code filters for request URLs with no extensions and treats them as navigation requests.</p><code-example path="universal/server.ts" header="server.ts (navigation)" region="navigation-request" linenums="false" ng-version="7.0.0"><div style="display:none">// All regular routes use the Universal engine app.get('*', (req, res) =&gt; { res.render('index', { req }); });</div><header class="ng-star-inserted">server.ts (navigation)</header><aio-code class="headed-code"><pre class="prettyprint lang-">      <button class="material-icons copy-button no-print ng-star-inserted" title="Copy code snippet" aria-label="Copy code snippet from server.ts (navigation)">
        <span aria-hidden="true">content_copy</span>
      </button>
      <code class="animated fadeIn"><span class="com">// All regular routes use the Universal engine</span><span class="pln">
app</span><span class="pun">.</span><span class="kwd">get</span><span class="pun">(</span><span class="str">'*'</span><span class="pun">,</span><span class="pln"> </span><span class="pun">(</span><span class="pln">req</span><span class="pun">,</span><span class="pln"> res</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  res</span><span class="pun">.</span><span class="pln">render</span><span class="pun">(</span><span class="str">'index'</span><span class="pun">,</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> req </span><span class="pun">});</span><span class="pln">
</span><span class="pun">});</span></code>
    </pre></aio-code></code-example><h3 id="serving-static-files-safely" translation-result="on">安全的提供静态文件<a title="Link to this heading" class="header-link" aria-hidden="true" href="guide/universal#serving-static-files-safely"><i class="material-icons">link</i></a></h3><h3 translation-origin="off" id="serving-static-files-safely">Serving static files safely<a title="Link to this heading" class="header-link" aria-hidden="true" href="guide/universal#serving-static-files-safely"><i class="material-icons">link</i></a></h3><p translation-result="on">单独的 <code>app.use()</code> 会处理所有其它 URL，比如对 JavaScript 、图片和样式表等静态资源的请求。</p><p translation-origin="off">A single <code>app.use()</code> treats all other URLs as requests for static assets such as JavaScript, image, and style files.</p><p translation-result="on">要保证客户端只能下载那些<em>允许</em>他们访问的文件，你应该把所有面向客户端的资源文件都放在 <code>/dist</code> 目录下，并且只允许客户端请求来自 <code>/dist</code> 目录下的文件。</p><p translation-origin="off">To ensure that clients can only download the files that they are permitted to see, put all client-facing asset files in the <code>/dist</code> folder and only honor requests for files from the <code>/dist</code> folder.</p><p translation-result="on">下列 Express 代码会把剩下的所有请求都路由到 <code>/dist</code> 目录下，如果文件未找到，就会返回 <code>404 - NOT FOUND</code>。</p><p translation-origin="off">The following Node Express code routes all remaining requests to <code>/dist</code>, and returns a <code>404 - NOT FOUND</code> error if the file isn't found.</p><code-example path="universal/server.ts" header="server.ts (static files)" region="static" linenums="false" ng-version="7.0.0"><div style="display:none">// Server <a href="api/upgrade/static" class="code-anchor">static</a> files from /<a href="api/animations/browser" class="code-anchor">browser</a> app.get('*.*', express.static(join(DIST_FOLDER, '<a href="api/animations/browser" class="code-anchor">browser</a>')));</div><header class="ng-star-inserted">server.ts (static files)</header><aio-code class="headed-code"><pre class="prettyprint lang-">      <button class="material-icons copy-button no-print ng-star-inserted" title="Copy code snippet" aria-label="Copy code snippet from server.ts (static files)">
        <span aria-hidden="true">content_copy</span>
      </button>
      <code class="animated fadeIn"><span class="com">// Server </span><a href="api/upgrade/static" class="code-anchor"><span class="com">static</span></a><span class="com"> files from /</span><a href="api/animations/browser" class="code-anchor"><span class="com">browser</span></a><span class="pln">
app</span><span class="pun">.</span><span class="kwd">get</span><span class="pun">(</span><span class="str">'*.*'</span><span class="pun">,</span><span class="pln"> express</span><span class="pun">.</span><span class="kwd">static</span><span class="pun">(</span><span class="kwd">join</span><span class="pun">(</span><span class="pln">DIST_FOLDER</span><span class="pun">,</span><span class="pln"> </span><span class="str">'</span><a href="api/animations/browser" class="code-anchor"><span class="str">browser</span></a><span class="str">'</span><span class="pun">)));</span></code>
    </pre></aio-code></code-example><h3 id="universal-in-action" translation-result="on">Universal 实战<a title="Link to this heading" class="header-link" aria-hidden="true" href="guide/universal#universal-in-action"><i class="material-icons">link</i></a></h3><h3 translation-origin="off" id="universal-in-action">Universal in action<a title="Link to this heading" class="header-link" aria-hidden="true" href="guide/universal#universal-in-action"><i class="material-icons">link</i></a></h3><p translation-result="on">打开浏览器，访问 <a href="http://localhost:4000/%E3%80%82">http://localhost:4000/。</a> 你会看到熟悉的《英雄指南》仪表盘页。</p><p translation-origin="off">Open a browser to <a href="http://localhost:4000/">http://localhost:4000/</a>. You should see the familiar Tour of Heroes dashboard page.</p><p translation-result="on">通过 <code>routerLinks</code> 进行导航可以正常工作了。 你可以从仪表盘前往英雄列表页，也可以返回。 也可以点击仪表盘页面上的一位英雄，并显示器详情页。</p><p translation-origin="off">Navigation via <code>routerLinks</code> works correctly. You can go from the Dashboard to the Heroes page and back. You can click a hero on the Dashboard page to display its Details page.</p><p translation-result="on">但要注意，点击、鼠标移动和键盘操作都是不行的。</p><p translation-origin="off">Notice, however, that clicks, mouse-moves, and keyboard entries are inert.</p><ul><li><p translation-result="on">点击英雄列表页中的英雄没反应。</p><p translation-origin="off">Clicking a hero on the Heroes page does nothing.</p></li><li><p translation-result="on">你也不能添加或删除英雄。</p><p translation-origin="off">You can't add or delete a hero.</p></li><li><p translation-result="on">仪表盘页面上的搜索框不理你。</p><p translation-origin="off">The search box on the Dashboard page is ignored.</p></li><li><p translation-result="on">详情页中的 <em>Back</em> 和 <em>Save</em> 按钮也没反应。</p><p translation-origin="off">The <em>Back</em> and <em>Save</em> buttons on the Details page don't work.</p></li></ul><p translation-result="on">除了点击 <code><a href="api/router/RouterLink" class="code-anchor">RouterLink</a></code> 之外的用户事件都不支持。你必须等待完整的客户端应用就绪。 直到你编译出了客户端应用，并把它们的输出移到 <code>dist/</code> 目录下之后，这个客户端应用才会就绪。</p><p translation-origin="off">User events other than <code><a href="api/router/RouterLink" class="code-anchor">routerLink</a></code> clicks aren't supported. You must wait for the full client app to arrive. It won't arrive until you compile the client app and move the output into the <code>dist/</code> folder.</p><p translation-result="on">在开发机上，从服务端渲染应用到客户端应用的转换完成的太快了。 你可以模拟一个慢速网络，来把这个转换过程看得更清楚一点，以便更好地欣赏在性能低、网络烂的设备上 Universal 应用的启动速度优势。</p><p translation-origin="off">The transition from the server-rendered app to the client app happens quickly on a development machine. You can simulate a slower network to see the transition more clearly and better appreciate the launch-speed advantage of a Universal app running on a low-powered, poorly connected device.</p><p translation-result="on">打开 Chrome 开发工具，并打开 Network 页。 在菜单栏的最右侧找到 <a href="https://developers.google.com/web/tools/chrome-devtools/network-performance/reference#throttling">Network Throttling（网络限流）</a> 下拉框。</p><p translation-origin="off">Open the Chrome Dev Tools and go to the Network tab. Find the <a href="https://developers.google.com/web/tools/chrome-devtools/network-performance/reference#throttling">Network Throttling</a> dropdown on the far right of the menu bar.</p><p translation-result="on">随便试一个 “3G” 速度。 服务端渲染的应用将会立即启动，不过加载完整的客户端应用可能要花几秒钟。</p><p translation-origin="off">Try one of the "3G" speeds. The server-rendered app still launches quickly but the full client app may take seconds to load.</p></div></div></aio-doc-viewer></main></mat-sidenav-content></mat-sidenav-container><div class="toc-container no-print ng-star-inserted"><aio-lazy-ce selector="aio-toc"><aio-toc ng-version="7.0.0"><div class="toc-inner no-print collapsed ng-star-inserted"><ul class="toc-list"><li title="Angular Universal：服务端渲染link" class="h1 ng-star-inserted active"><a href="guide/universal#angular-universal-server-side-rendering">Angular Universal：服务端渲染</a></li><li title="为何需要服务端渲染？link" class="h2 ng-star-inserted"><a href="guide/universal#why-use-server-side-rendering">为何需要服务端渲染？</a></li><li title="帮助网络爬虫link" class="h3 ng-star-inserted"><a href="guide/universal#facilitate-web-crawlers">帮助网络爬虫</a></li><li title="提升手机和低功耗设备上的性能link" class="h3 ng-star-inserted"><a href="guide/universal#improve-performance-on-mobile-and-low-powered-devices">提升手机和低功耗设备上的性能</a></li><li title="快速显示第一页link" class="h3 ng-star-inserted"><a href="guide/universal#show-the-first-page-quickly">快速显示第一页</a></li><li title="Universal Web 服务器link" class="h2 ng-star-inserted"><a href="guide/universal#universal-web-servers">Universal Web 服务器</a></li><li title="准备服务端渲染link" class="h2 ng-star-inserted"><a href="guide/universal#preparing-for-server-side-rendering">准备服务端渲染</a></li><li title="步骤一：安装依赖link" class="h2 ng-star-inserted"><a href="guide/universal#step-1-install-dependencies">步骤一：安装依赖</a></li><li title="步骤二：准备你的应用link" class="h2 ng-star-inserted"><a href="guide/universal#step-2-prepare-your-app">步骤二：准备你的应用</a></li><li title="2a. 为应用添加 Universal 支持link" class="h3 ng-star-inserted"><a href="guide/universal#2a-add-universal-support-to-your-app">2a. 为应用添加 Universal 支持</a></li><li title="2b. 创建服务端根模块link" class="h3 ng-star-inserted"><a href="guide/universal#2b-create-a-server-root-module">2b. 创建服务端根模块</a></li><li title="2c. 创建一个 main 文件，导出 AppServerModulelink" class="h3 ng-star-inserted"><a href="guide/universal#2c-create-a-main-file-to-export-appservermodule">2c. 创建一个 main 文件，导出 AppServerModule</a></li><li title="2d. 为 AppServerModule 创建配置文件link" class="h3 ng-star-inserted"><a href="guide/universal#2d-create-a-configuration-file-for-appservermodule">2d. 为 AppServerModule 创建配置文件</a></li><li title="步骤三：创建新的构建目标，并打包link" class="h2 ng-star-inserted"><a href="guide/universal#step-3-create-a-new-build-target-and-build-the-bundle">步骤三：创建新的构建目标，并打包</a></li><li title="步骤四：设置服务器环境，以运行 Universal 包link" class="h2 ng-star-inserted"><a href="guide/universal#step-4-set-up-a-server-to-run-universal-bundles">步骤四：设置服务器环境，以运行 Universal 包</a></li><li title="步骤五：打包并在服务器上运行此应用link" class="h2 ng-star-inserted"><a href="guide/universal#step-5-pack-and-run-the-app-on-the-server">步骤五：打包并在服务器上运行此应用</a></li><li title="创建一些脚本link" class="h3 ng-star-inserted"><a href="guide/universal#creating-scripts">创建一些脚本</a></li><li title="使用浏览器 APIlink" class="h3 ng-star-inserted"><a href="guide/universal#working-around-the-browser-apis">使用浏览器 API</a></li><li title="例子link" class="h2 ng-star-inserted"><a href="guide/universal#universal-tutorial">例子</a></li><li title="在 HTTP 中使用绝对地址link" class="h3 ng-star-inserted"><a href="guide/universal#using-absolute-urls-for-server-requests">在 HTTP 中使用绝对地址</a></li><li title="Universal 模板引擎link" class="h3 ng-star-inserted"><a href="guide/universal#universal-template-engine">Universal 模板引擎</a></li><li title="过滤请求的 URLlink" class="h3 ng-star-inserted"><a href="guide/universal#filtering-request-urls">过滤请求的 URL</a></li><li title="安全的提供静态文件link" class="h3 ng-star-inserted"><a href="guide/universal#serving-static-files-safely">安全的提供静态文件</a></li><li title="Universal 实战link" class="h3 ng-star-inserted"><a href="guide/universal#universal-in-action">Universal 实战</a></li></ul></div></aio-toc></aio-lazy-ce></div><footer class="no-print"><aio-footer><div class="grid-fluid"><div class="footer-block ng-star-inserted"><h3>资源</h3><ul><li class="ng-star-inserted"><a class="link" href="about" title="Angular 贡献者。">关于</a></li><li class="ng-star-inserted"><a class="link" href="resources" title="网络上的 Angular 工具、培训、博客等">资源列表</a></li><li class="ng-star-inserted"><a class="link" href="presskit" title="我们的联系方式、LOGO 和品牌">宣传资料</a></li><li class="ng-star-inserted"><a class="link" href="https://blog.angular.io/" title="Angular 官方博客">博客</a></li></ul></div><div class="footer-block ng-star-inserted"><h3>帮助</h3><ul><li class="ng-star-inserted"><a class="link" href="https://stackoverflow.com/questions/tagged/angular" title="Stack Overflow: 这里的社区会回答你关于 Angular 的技术问题">Stack Overflow</a></li><li class="ng-star-inserted"><a class="link" href="https://gitter.im/angular/angular" title="和老鸟聊 Angular">Gitter</a></li><li class="ng-star-inserted"><a class="link" href="https://github.com/angular/angular/issues" title="在 github 上报告问题和建议。">报告问题</a></li><li class="ng-star-inserted"><a class="link" href="https://github.com/angular/code-of-conduct/blob/master/CODE_OF_CONDUCT.md" title="让我们彼此尊重">行为规范</a></li></ul></div><div class="footer-block ng-star-inserted"><h3>社区</h3><ul><li class="ng-star-inserted"><a class="link" href="events" title="Post issues and suggestions on github.">活动</a></li><li class="ng-star-inserted"><a class="link" href="http://www.meetup.com/topics/angularjs/" title="参加聚会，向别的开发人员学习">聚会</a></li><li class="ng-star-inserted"><a class="link" href="https://twitter.com/angular" title="Twitter">Twitter</a></li><li class="ng-star-inserted"><a class="link" href="https://github.com/angular/angular" title="GitHub">GitHub</a></li><li class="ng-star-inserted"><a class="link" href="contribute" title="向 Angular 做贡献">做贡献</a></li></ul></div><div class="footer-block ng-star-inserted"><h3>多语言</h3><ul><li class="ng-star-inserted"><a class="link" href="https://angular.io/" title="English Version.">English Version</a></li><li class="ng-star-inserted"><a class="link" href="https://angular.jp/" title="日本語版">日本語版</a></li><li class="ng-star-inserted"><a class="link" href="https://angular.kr/" title="한국어">한국어</a></li></ul></div></div><p>Super-powered by Google ©2010-2019. 代码授权方式：<a href="license" title="License text">MIT-style License</a>. 文档授权方式：<a href="http://creativecommons.org/licenses/by/4.0/">CC BY 4.0</a>.</p><p>当前版本：8.0.0-build.95+sha.43aadf1.</p></aio-footer></footer><mat-icon class="cdk-visually-hidden mat-icon material-icons ng-star-inserted" role="img" aria-hidden="true">&nbsp;</mat-icon></aio-shell><noscript><div class="background-sky hero"></div><section id="intro" style="text-shadow:1px 1px #1976d2"><div class="hero-logo"><img src="assets/images/logos/angular/angular.svg" width="250" height="250" alt="Angular"></div><div class="homepage-container"><div class="hero-headline">一套框架，多种平台<br>移动 &amp; 桌面</div></div></section><h2 style="color:red;margin-top:40px;position:relative;text-align:center;text-shadow:1px 1px #fafafa"><b><i>该网站需要浏览器支持 JavaScript</i></b></h2></noscript><script src="runtime.fa3355727d5250409e08.js"></script><script src="polyfills.a2efc1c1a62312ff1f80.js"></script><script src="main.02884fe4cde5ede2ec4e.js"></script><div class="cdk-live-announcer-element cdk-visually-hidden" aria-atomic="true" aria-live="polite"></div></body></html>